1. 程式人生 > >java併發-Callable與Future

java併發-Callable與Future

基本概念:

  • Callable 介面類似於 Runnable,兩者都是為那些其例項可能被另一個執行緒執行的類設計的。但是 Runnable 不會返回結果,並且無法丟擲經過檢查的異常。
  • Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。計算完成後只能使用 get 方法來獲取結果,如有必要,計算完成前可以阻塞此方法。取消則由 cancel 方法來執行。還提供了其他方法,以確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。如果為了可取消性而使用 Future 但又不提供可用的結果,則可以宣告 Future

Callable

Callable位於java.util.concurrent包下,它也是一個介面,在它裡面也只聲明瞭一個方法,只不過這個方法叫做call():

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)

提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。
Future<?> submit(Runnable task) 提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。
<T> Future<T> submit(Runnable task, T result) 提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。

Future

 Future就是對於具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果。

boolean cancel(boolean mayInterruptIfRunning) 試圖取消對此任務的執行。
V get() 如有必要,等待計算完成,然後獲取其結果。
V get(long timeout, TimeUnit unit) 如有必要,最多等待為使計算完成所給定的時間之後,獲取其結果(如果結果可用)。
boolean isCancelled() 如果在任務正常完成前將其取消,則返回 true。
boolean isDone() 如果任務已完成,則返回 true。

FutureTask

我們可以看出FutureTask實現的是:RunnableFuture

public class FutureTask<V>
extends Object
implements RunnableFuture<V>

我們再看RunnableFuture

public interface RunnableFuture<V>
extends Runnable, Future<V>

可以看出RunnableFuture繼承了Runnable介面和Future介面,而FutureTask實現了RunnableFuture介面。所以它既可以作為Runnable被執行緒執行,又可以作為Future得到Callable的返回值。

例項1:Callable+Future

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

public class test5 {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> result = executor.submit(task);
        executor.shutdown();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("主執行緒在執行任務");

        try {
            System.out.println("task執行結果"+result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("所有任務執行完畢");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子執行緒在進行計算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum +=i;
        return sum;
    }
}

例項2:Callable+FutureTask

public class Test {
    public static void main(String[] args) {
        //第一種方式
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();

        //第二種方式,注意這種方式和第一種方式效果是類似的,只不過一個使用的是ExecutorService,一個使用的是Thread
        /*Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();*/

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("主執行緒在執行任務");

        try {
            System.out.println("task執行結果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("所有任務執行完畢");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子執行緒在進行計算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}