JAVA併發編程:線程併發工具類Callable、Future 和FutureTask的使用

1、基本介紹

  Runnable 是一個接口,在它裏面只聲明瞭一個 run()方法,由於 run()方法返回值爲 void 類型,所以在執行完任務之後無法返回任何結果。
  Callable 位於 java.util.concurrent 包下,它也是一個接口,在它裏面也只聲明 了一個方法,只不過這個方法叫做 call(),這是一個泛型接口,call()函數返回的類型就是傳遞進來的 V 類型。
  Future 就是對於具體的 Runnable 或者 Callable 任務的執行結果進行取消、查詢是否完成、獲取結果。必要時可以通過 get 方法獲取執行結果,該方法會阻塞直到任務返回結果。在Future類中一共有5個方法,如下圖所示。
在這裏插入圖片描述

  • cancel(boolean mayInterruptIfRunning) 方法:取消任務,如果任務已經完成、已經被取消或由於某些其他原因而無法取消,則此嘗試將失敗。 如果成功,並且在調用{@code cancel}時此任務尚未開始,則該任務永遠不會運行。 如果任務已經開始,則{@code mayInterruptIfRunning}參數確定是否應中斷執行該任務的線程以嘗試停止該任務。
  • get() 方法:獲取返回結果
  • get(long timeout, TimeUnit unit) 方法:獲取結果時設置等待時長
  • isCancelled() 方法:如果此任務在正常完成之前被取消,則返回{@code true}。
  • isDone() 方法:如果此任務完成,則返回{@code true}。

  由於Future 只是一個接口,無法直接用來創建對象使用,因此就有了下面的FutureTask。FutureTask 類實現了RunnableFuture 接口,RunnableFuture 繼承了Runnable接口和Future 接口,而FutureTask 實現了RunnableFuture 接口。所以它既可以作爲Runnable被線程執行,又可以作爲Future 得到Callable 的返回值。FutureTask,可取消的異步計算。 此類提供{@link Future}的基本實現,其中包含啓動和取消計算,查詢以查看計算是否完成以及檢索計算結果的方法。 只有在計算完成後才能檢索結果; 如果計算尚未完成,則{@code get}方法將阻塞。 一旦計算完成,就不能重新開始或取消計算(除非使用{@link #runAndReset}調用計算)。UML類圖如下所示,可清晰看到幾個類的關係。
在這裏插入圖片描述
  因此我們通過一個線程運行Callable,但是Thread 不支持構造方法中傳遞Callable的實例,所以我們需要通過FutureTask 把一個Callable 包裝成Runnable,然後再通過這個FutureTask 拿到Callable 運行後的返回值。要new 一個FutureTask的實例,有兩種方法,如下圖所示。
在這裏插入圖片描述

2、代碼示例

  • 類說明:Future的基本使用
package cn.lspj.ch2.future;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 類說明:Future的使用
 */
public class UseFuture {

    /**
     * 實現Callable接口,允許有返回值
     */
    private static class UseCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("Callable 子線程開始計算。。。。。。");
            int num = 0;
            for(int i=0;i<5000;i++){
                num += i;
            }
            System.out.println("Callable 線程計算結果爲 num =" + num);
            return num;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        UseCallable useCallable = new UseCallable();
        // 包裝
        FutureTask futureTask = new FutureTask(useCallable);
        new Thread(futureTask).start();
        System.out.println("獲取子線程Callable計算返回結果:" + futureTask.get());
    }

}

執行結果如下:
在這裏插入圖片描述

  • 類說明:Future的使用,演示在計算過程中中斷任務
package cn.lspj.ch2.future;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 類說明:Future的使用,演示在計算過程中中斷任務
 */
public class UseFuture {

    /**
     * 實現Callable接口,允許有返回值
     */
    private static class UseCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("Callable 子線程開始計算。。。。。。");
            int num = 0;
            for(int i=0;i<5000;i++){
                if(Thread.currentThread().isInterrupted()){
                    System.out.println("Callable 子線程計算任務被中斷了。。。。。。。。。。");
                    return null;
                }
                Thread.sleep(1);
                num += i;
                System.out.println("num=" + num);
            }
            System.out.println("Callable 線程計算結果爲 num =" + num);
            return num;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        UseCallable useCallable = new UseCallable();
        // 包裝
        FutureTask futureTask = new FutureTask(useCallable);
        new Thread(futureTask).start();
        Thread.sleep(35);
        Random r = new Random(10);
        if(r.nextInt() > 5){
            System.out.println("獲取子線程Callable計算返回結果:" + futureTask.get());
        } else {
            System.out.println("cancle..............");
            futureTask.cancel(true);
        }
    }

}

執行結果如下:
在這裏插入圖片描述
  從執行結果來看,在任務執行計算的過程中調用task的cancel(boolean mayInterruptIfRunning)方法中斷任務是可以達到中斷任務的目的,但是需要在執行計算的業務邏輯中使用Thread.currentThread().isInterrupted()判斷任務是否中斷,否則計算任務是不會主動中斷的。


備註:博主微信公衆號,不定期更新文章,歡迎掃碼關注。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章