天天看點

Java多線程--Future與Callable

Callable

Callable與Runnable類似,但是執行任務後能傳回結果;Future接口表示異步任務,它能拿到Callable的傳回值,即擷取結果。

Callable接口如下:

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

這是一個泛型接口,傳回的類型就是傳遞進來的類型,或者抛出異常。

使用: 一般作為參數,詳見後面的例子

Future

Future能具體的Runnable或者Callable任務的執行進行取消、查詢是否完成、擷取結果。

接口如下:

public interface Future<V> {
    // 取消對此任務的執行
    boolean  cancel(boolean mayInterruptIfRunning);
    // 如果在任務正常完成前将其取消,則傳回 true
    boolean  isCancelled(); 
    // 如果任務已完成傳回 true
    boolean  isDone(); 
    // 擷取執行結果,該方法會阻塞一直等到任務執行完成
    V  get() throws InterruptedException, ExecutionException; 
    // 最多等待為使計算完成所給定的時間之後,擷取其結果,如果逾時,結果傳回null
    V  get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
           

Future的實作類:FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
……
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
           

可以看到,FutureTask實作了Runnable和Future,既可以作為Runnable被線程執行,又可以作為Future得到Callable的傳回值。

FutureTask的兩個構造方法:

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
           

示例如下

使用場景:目前線程(線程A)需要依賴于另一個線程(線程B)的處理結果,而線程B處理結果需要一定的時間,Future模式就可以讓線程A的資料請求交給B,需要資料時再去get。而在B處理時A還能處理其他業務。

package com.learn;

import java.util.concurrent.Callable;

public class FooCallable implements Callable<String> {
    private String name;

    public FooCallable(String name) {
        this.name = name;
    }

    @Override
    public String call() throws Exception {
        System.out.println("Task任務執行");
        Thread.sleep();
        return name;
    }

}
package com.learn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class FutureTaskTest {

    public static void main(String[] args) {
        FooCallable a = new FooCallable("A");
        FutureTask<String> futureTask1 = new FutureTask<>(a);
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(futureTask1);

        System.out.println("主線程執行任務");
        try {
            if (!futureTask1.isDone()) { // 任務沒有完成,會等待,直到任務完成
                System.out.println("FutureTask執行結果" + futureTask1.get());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("All執行完畢");
    }

}
           

執行結果:

Task任務執行
主線程執行任務
FutureTask執行結果A
All執行完畢
           

示例2

采用submit(Callable)

package com.learn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureTaskTest {

    public static void main(String[] args) {
        FooCallable a = new FooCallable("A");
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> ret = executorService.submit(a);

        System.out.println("主線程執行任務");
        try {
            System.out.println("Task執行結果" + ret.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("All執行完畢");
    }

}