1. 程式人生 > 實用技巧 >【併發程式設計】6.執行緒控制工具類

【併發程式設計】6.執行緒控制工具類

1.Future、Callable、FutureTask

執行緒池提供的submit方法

<T> Future<T> submit(Callable<T> task); //Callable  call方法具有返回值,Future物件可以通過呼叫其get()方法來獲 取任務的執行結果。

<T> Future<T> submit(Runnable task, T result);  //需要你注意的是Runnable介面的實現類Task聲明瞭一個有 參建構函式 Task(Result r) ,建立Task物件的時候傳入了result物件,這樣就能在類Task的run()方法 中對result進行各種操作了。result相當於主執行緒和子執行緒之間的橋樑,通過它主子執行緒可以共享資料。

Future<?> submit(Runnable task);    //Runnable run方法沒有返回值  返回的Future僅用於判斷執行是否完成

在執行多個任務的時候,使用Java標準庫提供的執行緒池是非常方便的。我們提交的任務只需要實現Runnable介面,就可以讓執行緒池去執行。但是使用Runable介面無法獲取任務執行的結果。
於是Java提供了Callable介面,相比於Runable增加了返回值,並且Callable介面是一個泛型介面,可以返回指定型別的結果。

public interface Callable<V> {
    V call() throws Exception;
}

將Callable 最為執行緒池執行任務的引數 通過返回值Future就可以獲得call方法的實現中返回的結果值:

   public static void main(String[] args) throws Exception{
         //初始化執行緒池,實際開發中不建議這麼做
        ExecutorService threadPool =  Executors.newFixedThreadPool(2);
        Future reuslt = threadPool.submit(new Callable<Integer>() {
            //匿名內部類實現Callable介面
            @Override
            public Integer call() throws Exception {
                System.out.println("callable task run");
                return 10;
            }
        });
        //或者執行結果 會阻塞
        Integer num = (Integer) reuslt.get();
        System.out.println(num);
        threadPool.shutdown();
    }

//執行結果  
//callable task run
//10

Future

    boolean cancel(boolean mayInterruptIfRunning);   //取消任務的 方法
    boolean isCancelled(); //判斷任務是否已取消
    boolean isDone(); //判斷任務是否已結束
    V get() throws InterruptedException, ExecutionException; //任務執行結果  當前執行緒阻塞
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; //任務執行結果 超時機制  當前執行緒阻塞

FutureTask

 //介面關係
public class FutureTask<V> implements RunnableFuture<V>

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();//介面的多繼承
  }

//構造方法
FutureTask(Callable callable);
FutureTask(Runnable runnable, V result);

FutureTask實現了Runnable和Future介面,由於實現了Runnable 介面,所以可以將FutureTask物件作為任務提交給ThreadPoolExecutor去執行,也可以直接被Thread執行;
又因為實現了Future介面,所以也能用來獲得任務的執行結果。

//執行緒池執行FutureTask 並獲取結果
public static void main(String[] args) throws Exception{
        // 建立
        FutureTask futureTask  = new FutureTask<>(()-> 1+2);
        // 建立執行緒池
        ExecutorService es = Executors.newCachedThreadPool();
        // 提交
        Future future = es.submit(futureTask);
         // 獲取計算結果
        Integer result = (Integer) futureTask.get();
        System.out.println(result);
        es.shutdown();
    }

//直接由執行緒執行並且獲取結果
public static void main(String[] args) throws Exception{
        // 建立
        FutureTask futureTask  = new FutureTask<>(()-> 1+2);
        Thread th1 = new Thread(futureTask);
        th1.start();
        Integer result =(Integer) futureTask.get();
        System.out.println(result);
    }

2.CountDownLatch

CountDownLatch是Java 1.5提供的執行緒控制工具類,主要用來解決一個執行緒等待 多個執行緒的場景,可以類比旅遊團團長要等待所有的遊客到齊才能去下一個景點.

    //構造方法 指定計數器
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    //計數器 -1 
    countDownLatch.countDown();//完成後計數器-1

    ///等待計數器為0
    countDownLatch.await();

countDown()方法一般用於線上程池的任務中,注意進行異常捕獲,不然在await()時可能會造成一直阻塞。

    ExecutorService executorService =Executors.newFixedThreadPool(3);
    CountDownLatch cdl = new CountDownLatch(3);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            try {
                function1();
            } catch (Exception e) {
                //異常處理
                e.printStackTrace();
            }
            finally {
                cdl.countDown();
            }
        }
    });  

3.CyclicBarrier

4.CompletableFuture

5.CompletionService

6.ForkJoinPool、ForkJoinTask