[JAVA] Callable,Runnable比較與用法

編寫多執行緒程式是為了實作多工的同步執行,從而能夠更好地提高執行速度。一般有三種方法,
Thread,Runnable,Callable.

Runnable和Callable的區別是,
(1)Callable規定的方法是call(),Runnable規定的方法是run().
(2)Callable在執行後可返回值,而Runnable在執行後不能返回值
(3)call方法可以拋出異常,run方法不可以
(4)執行Callable會返回Future物件,表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過Future物件可以瞭解執行情況,可取消執行,還可獲取執行結果。

  1. 通過實現Runnable介面來創建Thread執行緒:
    步驟1:實作Runnable介面的類別:
    class SomeRunnable implements Runnable
    {
        public void run()
        {
          //do something here
        }
    }
    步驟2:創建一個類物件:
    Runnable oneRunnable = new SomeRunnable();

    步驟3:由Runnable創建一個Thread物件:
    Thread oneThread = new Thread(oneRunnable);
    步驟4:啟動執行緒:
    oneThread.start();
    至此,一個執行緒就創建完成了。
    注釋:執行緒的執行流程很簡單,當執行代碼oneThread.start();時,就會執行oneRunnable物件中的void run();方法,該方法執行完成後,執行緒就消亡了。
  2. 與方法1類似,通過實現Callable介面來創建Thread執行緒:其中,Callable介面(也只有一個方法)定義如下:
    public interface Callable<V>   
    {   
        V call() throws Exception;   
    }
    步驟1:創建實現Callable介面的類SomeCallable<Integer>(略);
    步驟2:創建一個類物件:
    Callable<Integer> oneCallable = new SomeCallable<Integer>();
    步驟3:由Callable<Integer>創建一個FutureTask<Integer>物件:
     FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
    注:FutureTask<Integer>是一個包裝器,它通過接受Callable<Integer>來創建,它同時實現了Future和Runnable介面。
    步驟4:由FutureTask<Integer>創建一個Thread物件:
    Thread oneThread = new Thread(oneTask);
    步驟5:啟動執行緒:
    oneThread.start();
    至此,一個執行緒就創建完成了。
  3. 通過繼承Thread類來創建一個執行緒:
    步驟1:定義一個繼承Thread類的子類:
    class SomeThead extends Thraad
    {
        public void run()
        {
         //do something here
        }
    }
    步驟2:構造子類的一個物件:
    SomeThread oneThread = new SomeThread();

    步驟3:啟動執行緒:
    oneThread.start();
    至此,一個執行緒就創建完成了。
    注:這種創建執行緒的方法不夠好,主要是因為其涉及運行機制問題,影響程式性能。
  4. 通過執行緒pool來創建執行緒:
    步驟1:創建執行緒pool:
    ExecutorService pool = Executors.newCachedThreadPool();
    步驟2:通過Runnable物件或Callable物件將任務提交給ExecutorService物件:
    Future<Integer> submit(Callable<Integer> task);
    注:Future是一個介面,它的定義如下:
    public interface Future<T>
    {
        V get() throws ...;
        V get(long timeout, TimeUnit unit) throws ...;
        void cancle(boolean mayInterrupt);
        boolean isCancelled();
        boolean isDone();
    }
    至此,一個執行緒就創建完成了。
    注:執行緒pool需叫用shutdown();方法來關閉。
  5. 通過事件分配執行緒直接使用程式中的原有執行緒:
    使用方法:
    直接叫用EventQueue類的靜態方法invokeLater():
    EventQueue.invokeLater(oneRunnable);
    注:叫用EventQueue.invokeLater(oneRunnable);會直接執行oneRunnable物件中的run()方法。