1. 程式人生 > 其它 >高併發程式設計-非同步-回顧-Callable&Future&FutureTask

高併發程式設計-非同步-回顧-Callable&Future&FutureTask

高併發程式設計-非同步-回顧-Callable&Future&FutureTask

一、Callable&Future&FutureTask簡介

  傳統的非同步操作通過Thread和Runnable建立執行緒,但是這兩種方法都面臨的一個問題就是沒有返回值,所以在JDK1.5之後提供了Callable介面來實現,Futrue和FutureTask就是配合Callable來使用的。

Callable和Runnable的程式碼對比

@FunctionalInterface
public interface Runnable {
    /**
     *
     
*/ public abstract void run(); } @FunctionalInterface public interface Callable<V> { /** * *丟擲異常 */ V call() throws Exception; }

Runnable 的缺陷:

  • 沒有返回值
  • 不能檢查丟擲異常

 Callable的call方法可以有返回值的,也可以定義丟擲的Exception,一般和Futrue配合使用,Futrue來監督任務的執行情況,取消任務,還可以獲取任務的執行結果。這是Callable比Runnable強大的地方

例項程式碼如下

public class ThreadTask {

    @SneakyThrows
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("開始執行Runnable");
            }
        }).start();
FutureTask task
= new FutureTask(new Callable() { @Override public Object call() throws Exception { System.out.println("開始執行Callable"); Thread.sleep(3000); return "返回任務結果"; } }); new Thread(task).start(); System.out.println(task.get()); } }

二、Futrue的主要功能

  Futrue的主要功能是對Callable任務的監督,取消、獲取結果,可以通過task.get()獲取結果,這個時候會一直阻塞,直到任務返回執行結果為止。

futrue提供的方法如下:

  • boolean cancel (boolean mayInterruptIfRunning) 取消任務的執行。引數指定是 否立即中斷任務執行,或者等等任務結束
  • boolean isCancelled () 任務是否已經取消,任務正常完成前將其取消,則返回 true
  • boolean isDone () 任務是否已經完成。需要注意的是如果任務正常終止、異常或 取消,都將返回true
  • V get () throws InterruptedException, ExecutionException 等待任務執行結束,然後獲得V型別的結果。InterruptedException 執行緒被中斷異常,ExecutionException任務執行異常,如果任務被取消,還會丟擲 CancellationException
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一樣,多了設定超時時間。 引數timeout指定超時時間,uint指定時間的單位,在列舉類TimeUnit中有相關的定 義。如果計算超時,將丟擲TimeoutException

三、利用 FutureTask 建立 Future

Futrue本質上採用FutureTask來實現的,可以把他理解為生產者和消費者的一箇中轉站,FutureTask把任務儲存任務的結果,同時更新狀態:未執行、正在處理、已完成等

使用方法如下:

public class FutureTaskDemo {

    @SneakyThrows
    public static void main(String[] args) {
        Task task=new Task();
        FutureTask<Integer> futureTask = new FutureTask<>(task);
        //作為執行緒入參
        new Thread(futureTask).start();
        //獲取執行結果
        System.out.println(futureTask.get());
    }
static class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("當前子執行緒執行緒名稱"+Thread.currentThread().getName()); int sum=0; for (int i = 0; i <100 ; i++) { sum+=1; } return sum; } } }

四、使用案例:塔機檢測的繫結錄入

在塔基錄入的時候,需要關聯黑匣子、關聯司機、繫結吊鉤視訊、繫結駕駛艙視訊,假設這些業務每個執行需要100ms,如果採用傳統的同步執行方式,需要400ms才能完成。如果採用Future的非同步執行,只需要100ms。

如下圖所示

示例程式碼如下:

public class FutureTaskDemoTwo {

    @SneakyThrows
    public static void main(String[] args) {
        FutureTask<String> ft1 = new FutureTask<>(new Task1());
        FutureTask<String> ft2 = new FutureTask<>(new Task2());
        FutureTask<String> ft3 = new FutureTask<>(new Task3());
        FutureTask<String> ft4 = new FutureTask<>(new Task4());
        //構建執行緒池
        ExecutorService executorService= Executors.newFixedThreadPool(5);
        executorService.submit(ft1);
        executorService.submit(ft2);
        executorService.submit(ft3);
        executorService.submit(ft4);


        //獲取執行結果
        System.out.println(ft1.get());
        System.out.println(ft2.get());
        System.out.println(ft3.get());
        System.out.println(ft4.get());
   }

    static class Task1 implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("關聯黑匣子");
            Thread.sleep(50);
            return "關聯黑匣子成功";
        }
    }

    static class Task2 implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("關聯司機");
            Thread.sleep(50);
            return "關聯司機成功";
        }
    }

    static class Task3 implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("關聯吊鉤視訊");
            Thread.sleep(50);
            return "關聯吊鉤視訊成功";
        }
    }

    static class Task4 implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("關聯駕駛艙視訊");
            Thread.sleep(50);
            return "關聯駕駛艙視訊成功";
        }
    }
}

五、Futrue的缺陷

Futrue是個非同步計算結果,通過isDown來檢查非同步是否完成,通過get來獲取返回的結果。在非同步的計算中Futrue是比較合適的,但是也有很多不足之處:

  • 任務阻塞:Future只提供了get()方法來獲取結果,並且是阻塞的,遇到了只能等待;
  • 無法鏈式呼叫:如果你希望在計算任務完成後執行特定動作,不能滿足。
  • 無法多工組合:如果你運行了多個任務,並期望在它們全部執行結束後執行特 定動作,那麼在Future中這是無能為力的;
  • 無異常處理