Java終結任務:Callable和Future

在這裏首先介紹下Callable和Future,咱們知道一般建立線程的2種方式,一種是直接繼承Thread,另一種就是實現Runnable接口,可是這兩種方式建立的線程不返回結果,而Callable是和Runnable相似的接口定義,可是經過實現Callable接口建立的線程能夠有返回值,返回值類型能夠任意定義。java

Callable接口

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

能夠看到,這是一個泛型接口,call()函數返回的類型就是傳遞進來的V類型。設計模式

那麼怎麼使用Callable呢?通常狀況下是配合ExecutorService來使用的,在ExecutorService接口中聲明瞭若干個submit方法的重載版本:異步

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

第一個submit方法裏面的參數類型就是Callable。Callable通常是和ExecutorService配合來使用的,經過ExecutorService的實例submit獲得Future對象。ide

Future

Future接口以下:函數

public interface Future<V> {
    boolean  cancel(boolean mayInterruptIfRunning);// 試圖取消對此任務的執行
    boolean  isCancelled();      // 若是在任務正常完成前將其取消,則返回true
    boolean  isDone();           // 若是任務已完成(無論是正常仍是異常),則返回true
    V  get() throws InterruptedException, ExecutionException; // 方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;
    // 用來獲取執行結果,若是在指定時間內,還沒獲取到結果,就直接返回null;
    V  get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

Future用於表示異步計算的結果。它的實現類是FutureTask。spa

若是不想分支線程阻塞主線程,又想取得分支線程的執行結果,就用FutureTask線程

FutureTask實現了RunnableFuture接口,這個接口的定義以下:設計

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

能夠看出RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實現了RunnableFuture接口。因此它既能夠做爲Runnable被線程執行,又能夠做爲Future獲得Callable的返回值。code

使用示例

package demo.future;
 
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
 
/**
 * 試驗 Java 的 Future 用法
 */
public class FutureTest {
 
    public static class Task implements Callable<String> {
        @Override
        public String call() throws Exception {
            String tid = String.valueOf(Thread.currentThread().getId());
            System.out.printf("Thread#%s : in call\n", tid);
            return tid;
        }
    }
 
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        List<Future<String>> results = new ArrayList<Future<String>>();
        ExecutorService es = Executors.newCachedThreadPool();
        for(int i=0; i<100;i++)
            results.add(es.submit(new Task()));
 
        for(Future<String> res : results)
            System.out.println(res.get());
    }
 
}

終結任務

持有Future對象,能夠調用cancel(),並所以可使用它來中斷某個特定任務,若是將ture傳遞給cancel(),那麼它就會擁有該線程上調用interrupt()以中止這個線程的權限。所以,cancel()是一種中斷由Executor啓動的單個線程的方式。對象

cancel()通常是搭配get()方法來使用的。比方說,有一種設計模式是設定特定的時間,而後去執行一個做業的線程,若是該做業可以在設定的時間內執行完畢,則直接返回結果,若是不能執行完畢,則中斷做業的執行,繼續執行下一個做業,在這種模式下,使用Callable和Future來實現是一個很是好的解決方案。

相關文章
相關標籤/搜索