1. 程式人生 > >Java中Callable實現多執行緒

Java中Callable實現多執行緒

一、Runnable和Callable< V >原始碼

先回顧一下Runnable和Callable< V >原始碼吧;

//Runnable 原始碼
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

//Callable<V>原始碼
public interface Callable<V> {
    //返回V物件
    V call() throws Exception;
}
  • 原始碼中得出基本資訊:
  • 1.Runnable和Callable< V >的原始碼真的是少到極致了。這應該是遵循設計原則中的介面隔離原則吧,二者都是定義了一個標準的函式,具體邏則是由其子類實現;
  • 2.Runnable 介面中宣告返回值為void的run方法;所以Runnable開啟的執行緒猶如脫繮駿馬任其馳騁難以掌控,結果導致兩個問題:1).無法直接獲取到執行緒執行執行的結果,需要藉助一個全域性變數;2)不能直接捕獲執行緒執行中的異常;
  • 正是由於Runnable的“無法無天”難以控制,所以Java中的Callable< v >應用而生;

  • 3.在Callable< v >原始碼可以看到與Runnable不同的是Callable< v >介面引入泛型V,在宣告的call函式返回V 並且丟擲Exception真的專門應對Runnable中的沒有返回值和捕獲異常的個問題的。

二、Callable< V >的非同步管理類Future< V >

Future< V >介面

正如上面說的與Runable相比Callable< v >開發了更多的管理操作的許可權,但是Callable中只有call函式,所以Java中提供了一個Future類用於管理Callable。然而Future< V >也同樣是一個介面:

//Future<V>原始碼
public interface Future<V> {
   //取消Task執行緒:引數 如果是執行緒正在執行,是否中斷;返回中斷結果:ture 中斷成功;false 中斷失敗
boolean cancel(boolean mayInterruptIfRunning); //判斷該Task是否已近取消 boolean isCancelled(); //判斷該Task是否完成 boolean isDone(); //獲取該執行緒返回的結果,如果執行緒為執行完阻塞,等待執行完再返回 V get() throws InterruptedException, ExecutionException; //獲取該執行緒返回的結果,設定超時,超時丟擲Exception V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future< V >定義標準函式的介面,基本功能:
  • 1.判斷當前任務是否完成
  • 2.中斷當前任務,判斷是否已近中斷
  • 3.阻塞或者設定超時,獲取非同步Task結果,
Future< V >的實現類FutureTask

在原始碼中FutureTask實現RunnableFuture< V > 介面,然而RunnableFuture< V > 同樣是實現了Runnable和Future< V > 介面;按照Java的繼承原則和特徵, 因此FutureTask實際中實現了Future< V >介面,同時也具備了Future的所用基本功能;

三、開啟Callable< V >非同步執行緒的基本方式

首先在Java中開啟非同步執行緒都應該會想到執行緒池吧,Callable同樣可以藉助執行緒池進行開啟關閉,其次Callable< V >非同步執行緒的開啟肯定是要藉助它的實行類FutureTask,上文中已經提到的FutureTask是implements了Runnable,所以FutureTask同樣可以藉助Thread類包裝直接執行;
1.執行緒池中的在ExecutorService中定義了< T > Future< T > submit(Callable< T > task)函式就是用於開始執行Callable< V >任務滴;
ExecutorService開啟Callable的demo程式碼:

public static void main(String[] args) {
        //執行緒池submit開啟多執行緒
try {
             CallableMThread mThread = new CallableMThread();
            ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
            Future<String> submit = threadPool.submit(mThread);
            String resualt = submit.get();
            System.out.println(resualt);
            threadPool.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

}
//內部類的實現Callable<V>開啟新執行緒方式
 class CallableMThread implements Callable<String> {

        @Override
        public String call() throws Exception {
            // TO DO
            return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
        }
    }

2.藉助Thread包裝開啟Callable< V >非同步執行緒

實現Callable< T >介面多執行緒例子

public static void main(String[] args) {
     try {
             //FutureTask啟動執行緒
            CallableMThread mThread = new CallableMThread();
            FutureTask<String> task = new FutureTask<String>(mThread);
             new Thread(task).start();
            //返回的String結果
            String resualt = task.get();
            System.out.println(resualt);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


}
//內部類的實現Callable<V>開啟新執行緒方式
 class CallableMThread implements Callable<String> {

        @Override
        public String call() throws Exception {
            // TO DO
            return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
        }
    }
}

3.Callable< V >開啟一組執行緒;
實際開發中有些特殊場景需求是最短時間內完協作成幾個Task,最後彙總結果呈現給使用者;這一類需求往往是十分重要的互動介面的需求,所以咋能不來個demo呢

public static void main(String[] args) {
    try {
        CallableMThread mThread = new CallableMThread();
        int coreSize = Runtime.getRuntime().availableProcessors();
        //建立一個執行緒
        ExecutorService executor = Executors.newFixedThreadPool(coreSize);
        //建立多個有返回值的任務
        List<Future> list = new LinkedList<Future>();
        for (int i = 0; i < coreSize; i++) {
            FutureTask task = new FutureTask(mThread);
            //執行任務並獲取future
            Future future = executor.submit(task);
            list.add(future);
        }
            //關閉執行緒池
            executor.shutdown();
            //獲取併發任務結果
            for (Future mFuture : list) {
                //Future物件獲取返回值
                String resualt = mFuture.get().toString();
                //輸出結果
                System.out.printf(resualt);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

}
//內部類的實現Callable<V>開啟新執行緒方式
 class CallableMThread implements Callable<String> {

        @Override
        public String call() throws Exception {
            // TO DO
            return "ThreadID :" + Thread.currentThread().getId() + " ThreadRandom :" + (Math.random() * 1000);
        }
    }