併發-9-Callable和Future

Coding挖掘機發表於2019-02-22

我們原來所說的繼承Thread或者實現Runnable的方式都無法獲得執行緒的執行結果,除非使用共享變數或者執行緒通訊,我們先看一下Runnable介面的原始碼:

public interface Runnable{
    public abstract void run(){
    }
}
複製程式碼

run()的返回值為void,在任務執行完之後沒有返回

繼承Thread和實現Runnable這兩種方式,都無法獲得執行緒執行的結果

Callable可以彌補這一個缺點:

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

複製程式碼

是一個泛型介面,返回值型別為傳入進來的的T型別的值

注意:Callable中方法是call而不是run

使用Callable

一般配合ExecutorService來使用:

其中宣告瞭若干個過載的submit方法

<T> Future<T> submit(Callable<T> task);

<T> Future<T> submit(Runnable task, T result);    //一般不使用

Future<?> submit(Runnable task);
複製程式碼

Future

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

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)

        throws InterruptedException, ExecutionException, TimeoutException;

}

複製程式碼

cancel:取消任務

mayInterruptIfRunning:是否可以取消正在執行的任務

isCancelled:是否成功取消

isDone:是否已經完成

get:獲取執行結果,一直等到任務執行完畢才返回,阻塞等待

get(long timeout, TimeUint unit):用來獲取執行結果,指定時間內,還沒有獲取到結果,就返回null

也就是說Future用於非同步獲取執行結果或取消執行任務提供了三種功能:

  1)判斷任務是否完成;

  2)能夠中斷任務;

  3)能夠獲取任務執行結果。

因為Future只是一個介面,所以是無法直接用來建立物件使用的,因此就有了下面的FutureTask。

FutureTask是Future的唯一實現

public interface RunnableFuture<V> extends Runnbale,Future<V>
    void run()
}

public class FutureTask implements RunnbaleFuture<V>{
    public FutureTask(Callable<V> callable)
    public FutureTask(Runnable runnable,V result)
}

複製程式碼

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

這段程式碼不給答案啦,動手實踐感受一下

public class FutureTaskUseDemo {

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

        ExecutorService executor = Executors.newCachedThreadPool();

        /**
         * 使用FutureTask的Runnable特性
         */
        Thread thread = new Thread(new FutureTask<>(new BoilWater()));
        thread.start();

        /**
         * 使用FutureTask的Callable特性------第一種寫法
         */
        FutureTask futureTask = new FutureTask(new BoilWater());
        executor.submit(futureTask);

        out.println("做飯");
        Thread.sleep(2000);
        out.println("飯做好了");

        while (!futureTask.isDone()) {
            out.println("水還沒燒開呢");
            Thread.sleep(1000);
        }

        out.println(futureTask.get());

        /**
         * 使用FutureTask的Callable特性------第二種寫法
         */
        Future<String> submit = executor.submit(new BoilWater());

        out.println("做飯");
        Thread.sleep(2000);
        out.println("飯做好了");

        while (!submit.isDone()) {
            out.println("水還沒燒開呢");
            Thread.sleep(1000);
        }

        out.println(submit.get());

        /**
         * 多個任務同時並行
         */
        CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(executor);
        for (int i = 0; i < 5; i++) {
            final int taskId = i;
            cs.submit(() -> taskId);
        }
        for (int i = 0; i < 5; i++) {
            try {
                out.println(cs.take().get());
            } catch (Exception e) {

            }
        }
    }
}

class BoilWater implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(5000);
        return System.currentTimeMillis() + " 水燒開了";
    }
}
複製程式碼

相關文章