Java多线程系列--“JUC线程池”06之 Callable和Future

 

概要

本章介绍线程池中的Callable和Future。
Callable 和 Future 简介
示例和源码分析(基于JDK1.7.0_40)html

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3544116.htmljava

 

Callable 和 Future 简介

  Callable 和 Future 是比较有趣的一对组合。当咱们须要获取线程的执行结果时,就须要用到它们。Callable用于产生结果,Future用于获取结果。多线程

1. Callable架构

Callable 是一个接口,它只包含一个call()方法。Callable是一个返回结果而且可能抛出异常的任务。异步

为了便于理解,咱们能够将Callable比做一个Runnable接口,而Callable的call()方法则相似于Runnable的run()方法。ide

Callable的源码以下:函数

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

说明:从中咱们能够看出Callable支持泛型。源码分析

 

2. Futurethis

Future 是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。spa

Future的源码以下:

public interface Future<V> {
    // 试图取消对此任务的执行。
    boolean     cancel(boolean mayInterruptIfRunning)

    // 若是在任务正常完成前将其取消,则返回 true。
    boolean     isCancelled()

    // 若是任务已完成,则返回 true。
    boolean     isDone()

    // 若有必要,等待计算完成,而后获取其结果。
    V           get() throws InterruptedException, ExecutionException;

    // 若有必要,最多等待为使计算完成所给定的时间以后,获取其结果(若是结果可用)。
    V             get(long timeout, TimeUnit unit)
          throws InterruptedException, ExecutionException, TimeoutException;
}

说明: Future用于表示异步计算的结果。它的实现类是FutureTask,在讲解FutureTask以前,咱们先看看Callable, Future, FutureTask它们之间的关系图,以下:

说明
(01) RunnableFuture是一个接口,它继承了Runnable和Future这两个接口。RunnableFuture的源码以下:

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

(02) FutureTask实现了RunnableFuture接口。因此,咱们也说它实现了Future接口。

 

示例和源码分析(基于JDK1.7.0_40)

咱们先经过一个示例看看Callable和Future的基本用法,而后再分析示例的实现原理。

 1 import java.util.concurrent.Callable;
 2 import java.util.concurrent.Future;
 3 import java.util.concurrent.Executors;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.ExecutionException;
 6 
 7 class MyCallable implements Callable {
 8 
 9     @Override 
10     public Integer call() throws Exception {
11         int sum    = 0;
12         // 执行任务
13         for (int i=0; i<100; i++)
14             sum += i;
15         //return sum; 
16         return Integer.valueOf(sum);
17     } 
18 }
19 
20 public class CallableTest1 {
21 
22     public static void main(String[] args) 
23         throws ExecutionException, InterruptedException{
24         //建立一个线程池
25         ExecutorService pool = Executors.newSingleThreadExecutor();
26         //建立有返回值的任务
27         Callable c1 = new MyCallable();
28         //执行任务并获取Future对象 
29         Future f1 = pool.submit(c1);
30         // 输出结果
31         System.out.println(f1.get()); 
32         //关闭线程池 
33         pool.shutdown(); 
34     }
35 }

运行结果

4950

结果说明
  在主线程main中,经过newSingleThreadExecutor()新建一个线程池。接着建立Callable对象c1,而后再经过pool.submit(c1)将c1提交到线程池中进行处理,而且将返回的结果保存到Future对象f1中。而后,咱们经过f1.get()获取Callable中保存的结果;最后经过pool.shutdown()关闭线程池。

 

1. submit()

submit()在java/util/concurrent/AbstractExecutorService.java中实现,它的源码以下:

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    // 建立一个RunnableFuture对象
    RunnableFuture<T> ftask = newTaskFor(task);
    // 执行“任务ftask”
    execute(ftask);
    // 返回“ftask”
    return ftask;
}

说明:submit()经过newTaskFor(task)建立了RunnableFuture对象ftask。它的源码以下:

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

 

2. FutureTask的构造函数

FutureTask的构造函数以下:

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    // callable是一个Callable对象
    this.callable = callable;
    // state记录FutureTask的状态
    this.state = NEW;       // ensure visibility of callable
}

 

3. FutureTask的run()方法

咱们继续回到submit()的源码中。
在newTaskFor()新建一个ftask对象以后,会经过execute(ftask)执行该任务。此时ftask被看成一个Runnable对象进行执行,最终会调用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中实现,源码以下:

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        // 将callable对象赋值给c。
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 执行Callable的call()方法,并保存结果到result中。
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            // 若是运行成功,则将result保存
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        // 设置“state状态标记”
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

说明run()中会执行Callable对象的call()方法,而且最终将结果保存到result中,并经过set(result)将result保存。
      以后调用FutureTask的get()方法,返回的就是经过set(result)保存的值。

 


更多内容

1. Java多线程系列--“JUC线程池”02之 线程池原理(一)

2. Java多线程系列--“JUC线程池”03之 线程池原理(二)

3. Java多线程系列--“JUC线程池”04之 线程池原理(三)

4. Java多线程系列--“JUC线程池”05之 线程池原理(四)

5. Java多线程系列--“JUC线程池”01之 线程池架构

6. Java多线程系列目录(共xx篇)

相关文章
相关标签/搜索