Java Executor 框架

Java Executor 框架

Executor框架是指java5中引入的一系列并发库中与executor相关的功能类,包括Executor、Executors、 ExecutorService、CompletionService、Future、Callable等。(图片引用自 http://www.javaclubcn.com/a/jichuzhishi/2012/1116/170.html)

本篇博文分析Executor中几个比较重要的接口和类。

Executor

1 public interface Executor {
2      void execute(Runnable command);
3 }

Executor接口是Executor框架中最基础的部分,定义了一个用于执行Runnable的execute方法。它没有直接的实现类,有一个重要的子接口ExecutorService。

ExecutorService

 1 //继承自Executor接口
 2 public interface ExecutorService extends Executor {
 3     /**
 4      * 关闭方法,调用后执行之前提交的任务,不再接受新的任务
 5      */
 6     void shutdown();
 7     /**
 8      * 从语义上可以看出是立即停止的意思,将暂停所有等待处理的任务并返回这些任务的列表
 9      */
10     List<Runnable> shutdownNow();
11     /**
12      * 判断执行器是否已经关闭
13      */
14     boolean isShutdown();
15     /**
16      * 关闭后所有任务是否都已完成
17      */
18     boolean isTerminated();
19     /**
20      * 中断
21      */
22     boolean awaitTermination(long timeout, TimeUnit unit)
23         throws InterruptedException;
24     /**
25      * 提交一个Callable任务
26      */
27     <T> Future<T> submit(Callable<T> task);
28     /**
29      * 提交一个Runable任务,result要返回的结果
30      */
31     <T> Future<T> submit(Runnable task, T result);
32     /**
33      * 提交一个任务
34      */
35     Future<?> submit(Runnable task);
36     /**
37      * 执行所有给定的任务,当所有任务完成,返回保持任务状态和结果的Future列表
38      */
39     <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
40         throws InterruptedException;
41     /**
42      * 执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
43      */
44     <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
45                                   long timeout, TimeUnit unit)
46         throws InterruptedException;
47     /**
48      * 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
49      */
50     <T> T invokeAny(Collection<? extends Callable<T>> tasks)
51         throws InterruptedException, ExecutionException;
52     /**
53      * 执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
54      */
55     <T> T invokeAny(Collection<? extends Callable<T>> tasks,
56                     long timeout, TimeUnit unit)
57         throws InterruptedException, ExecutionException, TimeoutException;
58 }

ExecutorService接口继承自Executor接口,定义了终止、提交任务、跟踪任务返回结果等方法。

ExecutorService涉及到Runnable、Callable、Future接口,这些接口的具体内容如下。

 1 // 实现Runnable接口的类将被Thread执行,表示一个基本的任务
 2 public interface Runnable {
 3     // run方法就是它所有的内容,就是实际执行的任务
 4     public abstract void run();
 5 }
 6 // Callable同样是任务,与Runnable接口的区别在于它接收泛型,同时它执行任务后带有返回内容
 7 public interface Callable<V> {
 8     // 相对于run方法的带有返回值的call方法
 9     V call() throws Exception;
10 }

Future

ExecutorService有一个子接口ScheduledExecutorService和一个抽象实现类AbstractExecutorService。

ScheduledExecutorService

 1 // 可以安排指定时间或周期性的执行任务的ExecutorService
 2 public interface ScheduledExecutorService extends ExecutorService {
 3     /**
 4      * 在指定延迟后执行一个任务,只执行一次
 5      */
 6     public ScheduledFuture<?> schedule(Runnable command,
 7                        long delay, TimeUnit unit);
 8     /**
 9      * 与上面的方法相同,只是接受的是Callable任务
10      */
11     public <V> ScheduledFuture<V> schedule(Callable<V> callable,
12                        long delay, TimeUnit unit);
13     /**
14      * 创建并执行一个周期性的任务,在initialDelay延迟后每间隔period个单位执行一次,时间单位都是unit
15      * 每次执行任务的时间点是initialDelay, initialDelay+period, initialDelay + 2 * period...
16      */
17     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
18                           long initialDelay,
19                           long period,
20                           TimeUnit unit);
21     /**
22      * 创建并执行一个周期性的任务,在initialDelay延迟后开始执行,在执行结束后再延迟delay个单位开始执行下一次任务,时间单位都是unit
23      * 每次执行任务的时间点是initialDelay, initialDelay+(任务运行时间+delay), initialDelay + 2 * (任务运行时间+delay)...
24      */
25     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
26                              long initialDelay,
27                              long delay,
28                              TimeUnit unit);
29 }

ScheduledExecutorService定义了四个方法,已经在上面给出基本的解释。ScheduledExecutorService有 两个实现类,分别是DelegatedScheduledExecutorService和ScheduledThreadPoolExecutor,将 在后面介绍。还需要解释的是ScheduledFuture。

ScheduledFuture继承自Future和Delayed接口,自身没有添加方法。Delayed接口定义了一个获取剩余延迟的方法。

AbstractExecutorService

  1 // 提供ExecutorService的默认实现
  2 public abstract class AbstractExecutorService implements ExecutorService {
  3     /*
  4      * 为指定的Runnable和value构造一个FutureTask,value表示默认被返回的Future
  5      */
  6     protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
  7         return new FutureTask<T>(runnable, value);
  8     }
  9     /*
 10      * 为指定的Callable创建一个FutureTask
 11      */
 12     protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
 13         return new FutureTask<T>(callable);
 14     }
 15     /*
 16      * 提交Runnable任务
 17      */
 18     public Future<?> submit(Runnable task) {
 19         if (task == null) throw new NullPointerException();
 20         // 通过newTaskFor方法构造RunnableFuture,默认的返回值是null
 21         RunnableFuture<Object> ftask = newTaskFor(task, null);
 22         // 调用具体实现的execute方法
 23         execute(ftask);
 24         return ftask;
 25     }
 26     /*
 27      * 提交Runnable任务
 28      */
 29     public <T> Future<T> submit(Runnable task, T result) {
 30         if (task == null) throw new NullPointerException();
 31         // 通过newTaskFor方法构造RunnableFuture,默认的返回值是result
 32         RunnableFuture<T> ftask = newTaskFor(task, result);
 33         execute(ftask);
 34         return ftask;
 35     }
 36     /*
 37      * 提交Callable任务
 38      */
 39     public <T> Future<T> submit(Callable<T> task) {
 40         if (task == null) throw new NullPointerException();
 41         RunnableFuture<T> ftask = newTaskFor(task);
 42         execute(ftask);
 43         return ftask;
 44     }
 45
 46     /*
 47      * doInvokeAny的具体实现(核心内容),其它几个方法都是重载方法,都对这个方法进行调用
 48      * tasks 是被执行的任务集,timed标志是否定时的,nanos表示定时的情况下执行任务的限制时间
 49      */
 50     private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
 51                             boolean timed, long nanos)
 52         throws InterruptedException, ExecutionException, TimeoutException {
 53         // tasks空判断
 54         if (tasks == null)
 55             throw new NullPointerException();
 56         // 任务数量
 57         int ntasks = tasks.size();
 58         if (ntasks == 0)
 59             throw new IllegalArgumentException();
 60         // 创建对应数量的Future返回集
 61         List<Future<T>> futures= new ArrayList<Future<T>>(ntasks);
 62         ExecutorCompletionService<T> ecs =
 63             new ExecutorCompletionService<T>(this);
 64         try {
 65             // 执行异常
 66             ExecutionException ee = null;
 67             // System.nanoTime()根据系统计时器当回当前的纳秒值
 68             long lastTime = (timed)? System.nanoTime() : 0;
 69             // 获取任务集的遍历器
 70             Iterator<? extends Callable<T>> it = tasks.iterator();
 71
 72             // 向执行器ExecutorCompletionService提交一个任务,并将结果加入futures中
 73             futures.add(ecs.submit(it.next
 74             // 修改任务计数器
 75             --ntasks;
 76             // 活跃任务计数器
 77             int active = 1;
 78             for (;;) {
 79                 // 获取并移除代表已完成任务的Future,如果不存在,返回null
 80                 Future<T> f = ecs.poll();
 81                 if (f == null) {
 82                     // 没有任务完成,且任务集中还有未提交的任务
 83                     if (ntasks > 0) {
 84                         // 剩余任务计数器减1
 85                         --ntasks;
 86                         // 提交任务并添加结果
 87                         futures.add(ecs.submit(it.next()));
 88                         // 活跃任务计数器加1
 89                         ++active;
 90                     }
 91                     // 没有剩余任务,且没有活跃任务(所有任务可能都会取消),跳过这一次循环
 92                     else if (active == 0)
 93                         break;
 94                     else if (timed) {
 95                         // 获取并移除代表已完成任务的Future,如果不存在,会等待nanos指定的纳秒数
 96                         f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
 97                         if (f == null)
 98                             throw new TimeoutException();
 99                         // 计算剩余可用时间
100                         long now = System.nanoTime();
101                         nanos -= now - lastTime;
102                         lastTime = now;
103                     }
104                     else
105                         // 获取并移除表示下一个已完成任务的未来,等待,如果目前不存在。
106                         // 执行到这一步说明已经没有任务任务可以提交,只能等待某一个任务的返回
107                         f = ecs.take();
108                 }
109                 // f不为空说明有一个任务完成了
110                 if (f != null) {
111                     // 已完成一个任务,所以活跃任务计数减1
112                     --active;
113                     try {
114                         // 返回该任务的结果
115                         return f.get();
116                     } catch (InterruptedException ie) {
117                         throw ie;
118                     } catch (ExecutionException eex) {
119                         ee = eex;
120                     } catch (RuntimeException rex) {
121                         ee = new ExecutionException(rex);
122                     }
123                 }
124             }
125             // 如果没有成功返回结果则抛出异常
126             if (ee == null)
127                 ee = new ExecutionException();
128             throw ee;
129
130         } finally {
131             // 无论执行中发生异常还是顺利结束,都将取消剩余未执行的任务
132             for (Future<T> f : futures)
133                 f.cancel(true);
134         }
135     }
136
137     public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
138         throws InterruptedException, ExecutionException {
139         try {
140             // 非定时任务的doInvokeAny调用
141             return doInvokeAny(tasks, false, 0);
142         } catch (TimeoutException cannotHappen) {
143             assert false;
144             return null;
145         }
146     }
147     // 定时任务的invokeAny调用,timeout表示超时时间,unit表示时间单位
148     public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
149                            long timeout, TimeUnit unit)
150         throws InterruptedException, ExecutionException, TimeoutException {
151         return doInvokeAny(tasks, true, unit.toNanos(timeout));
152     }
153     // 无超时设置的invokeAll方法
154     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
155         throws InterruptedException {
156         // 空任务判断
157         if (tasks == null)
158             throw new NullPointerException();
159         // 创建大小为任务数量的结果集
160         List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
161         // 是否完成所有任务的标记
162         boolean done = false;
163         try {
164             // 遍历并执行任务
165             for (Callable<T> t : tasks) {
166                 RunnableFuture<T> f = newTaskFor(t);
167                 futures.add(f);
168                 execute(f);
169             }
170             // 遍历结果集
171             for (Future<T> f : futures) {
172                 // 如果某个任务没完成,通过f调用get()方法
173                 if (!f.isDone()) {
174                     try {
175                         // get方法等待计算完成,然后获取结果(会等待)。所以调用get后任务就会完成计算,否则会等待
176                         f.get();
177                     } catch (CancellationException ignore) {
178                     } catch (ExecutionException ignore) {
179                     }
180                 }
181             }
182             // 标志所有任务执行完成
183             done = true;
184             // 返回结果
185             return futures;
186         } finally {
187             // 假如没有完成所有任务(可能是发生异常等情况),将任务取消
188             if (!done)
189                 for (Future<T> f : futures)
190                     f.cancel(true);
191         }
192     }
193     // 超时设置的invokeAll方法
194     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
195                                          long timeout, TimeUnit unit)
196         throws InterruptedException {
197         // 需要执行的任务集为空或时间单位为空,抛出异常
198         if (tasks == null || unit == null)
199             throw new NullPointerException();
200         // 将超时时间转为纳秒单位
201         long nanos = unit.toNanos(timeout);
202         // 创建任务结果集
203         List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
204         // 是否全部完成的标志
205         boolean done = false;
206         try {
207             // 遍历tasks,将任务转为RunnableFuture
208             for (Callable<T> t : tasks)
209                 futures.add(newTaskFor(t));
210             // 记录当前时间(单位是纳秒)
211             long lastTime = System.nanoTime();
212             // 获取迭代器
213             Iterator<Future<T>> it = futures.iterator();
214             // 遍历
215             while (it.hasNext()) {
216                 // 执行任务
217                 execute((Runnable)(it.next()));
218                 // 记录当前时间
219                 long now = System.nanoTime();
220                 // 计算剩余可用时间
221                 nanos -= now - lastTime;
222                 // 更新上一次执行时间
223                 lastTime = now;
224                 // 超时,返回保存任务状态的结果集
225                 if (nanos <= 0)
226                     return futures;
227             }
228
229             for (Future<T> f : futures) {
230                 // 如果有任务没完成
231                 if (!f.isDone()) {
232                     // 时间已经用完,返回保存任务状态的结果集
233                     if (nanos <= 0)
234                         return futures;
235                     try {
236                         // 获取计算结果,最多等待给定的时间nanos,单位是纳秒
237                         f.get(nanos, TimeUnit.NANOSECONDS);
238                     } catch (CancellationException ignore) {
239                     } catch (ExecutionException ignore) {
240                     } catch (TimeoutException toe) {
241                         return futures;
242                     }
243                     // 计算可用时间
244                     long now = System.nanoTime();
245                     nanos -= now - lastTime;
246                     lastTime = now;
247                 }
248             }
249             // 修改是否全部完成的标记
250             done = true;
251             // 返回结果集
252             return futures;
253         } finally {
254             // 假如没有完成所有任务(可能是时间已经用完、发生异常等情况),将任务取消
255             if (!done)
256                 for (Future<T> f : futures)
257                     f.cancel(true);
258         }
259     }
260 }

AbstractExecutor实现了ExecutorService接口的部分方法。具体代码的分析在上面已经给出。

AbstractExecutor有两个子类:DelegatedExecutorService、ThreadPoolExecutor。将在后面介绍。

下面是AbstractExecutor中涉及到的RunnableFuture、FutureTask、ExecutorCompletionService。

RunnableFuture继承自Future和Runnable,只有一个run()方法(Runnable中已经有一个run方法了,为什么 RunnableFuture还要重新写一个run方法呢?求高手指教)。RunnableFuture接口看上去就像是Future和Runnable 两个接口的组合。

FutureTask实现了RunnableFuture接口,除了实现了Future和Runnable中的方法外,它还有自己的方法和一个内部类Sync。

ExecutorCompletionService实现了CompletionService接口,将结果从复杂的一部分物种解耦出来。这些内容后续会介绍,不过这里先介绍框架中的其它内容,弄清整体框架。

下面看继承自AbstractExecutorService的ThreadPoolExecutor。

ThreadPoolExecutor

ThreadPoolExecutor(好长)

可以参考http://xtu-xiaoxin.iteye.com/blog/647744

从上面的框架结构图中可以可以看出剩下的就是ScheduledThreadPoolExecutor和Executors。Executors是一个工具类,提供一些工厂和实用方法。

下面看ScheduledThreadPoolExecutor,它继承自ThreadPoolExecutor并实现了ScheduledExecutorService接口。

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor

在代码中都加了注释,我想大致能解释清楚吧。

Executor涉及的类还是比较多的,到此为止剩下的还有Executors

Executors

Executors中所定义的 ExecutorExecutorServiceScheduledExecutorServiceThreadFactoryCallable 类的工厂和实用方法。此类支持以下各种方法:

  • 创建并返回设置有常用配置字符串的 ExecutorService 的方法。
  • 创建并返回设置有常用配置字符串的 ScheduledExecutorService 的方法。
  • 创建并返回“包装的”ExecutorService 方法,它通过使特定于实现的方法不可访问来禁用重新配置。
  • 创建并返回 ThreadFactory 的方法,它可将新创建的线程设置为已知的状态。
  • 创建并返回非闭包形式的 Callable 的方法,这样可将其用于需要 Callable 的执行方法中。

Executors提供的都是工具形式的方法,所以都是static的,并且这个类也没有必要实例化,所以它的构造方法时private的。下面主要看一下几个内部类。

   RunnableAdapter

 1 static final class RunnableAdapter<T> implements Callable<T> {
 2         final Runnable task;
 3         final T result;
 4         RunnableAdapter(Runnable  task, T result) {
 5             this.task = task;
 6             this.result = result;
 7         }
 8         public T call() {
 9             task.run();
10             return result;
11         }
12 }

适配器。以Callable的形式执行Runnable并且返回给定的result。

PrivilegedCallable

 1 static final class PrivilegedCallable<T> implements Callable<T> {
 2     private final AccessControlContext acc;
 3     private final Callable<T> task;
 4     private T result;
 5     private Exception exception;
 6     PrivilegedCallable(Callable<T> task) {
 7         this.task = task;
 8         this.acc = AccessController.getContext();
 9     }
10
11     public T call() throws Exception {
12         AccessController.doPrivileged(new PrivilegedAction<T>() {
13             public T run() {
14                 try {
15                     result = task.call();
16                 } catch (Exception ex) {
17                     exception = ex;
18                 }
19                 return null;
20             }
21         }, acc);
22         if (exception != null)
23             throw exception;
24         else
25             return result;
26     }
27 }

在访问控制下运行的Callable。涉及到Java.security包中的内容。

PrivilegedCallableUsingCurrentClassLoader类与上面的PrivilegedCallable类似,只是使用的是CurrentClassLoader。

DefaultThreadFactory

 1     static class DefaultThreadFactory implements ThreadFactory {
 2         static final AtomicInteger poolNumber = new AtomicInteger(1);
 3         final ThreadGroup group;
 4         final AtomicInteger threadNumber = new AtomicInteger(1);
 5         final String namePrefix;
 6
 7         DefaultThreadFactory() {
 8             SecurityManager s = System.getSecurityManager();
 9             group = (s != null)? s.getThreadGroup() :
10                                  Thread.currentThread().getThreadGroup();
11             namePrefix = "pool-" +
12                           poolNumber.getAndIncrement() +
13                          "-thread-";
14         }
15
16         public Thread newThread(Runnable r) {
17             // 调用Thread构造方法创建线程
18             Thread t = new Thread(group, r,
19                                   namePrefix + threadNumber.getAndIncrement(),
20                                   0);
21             // 取消守护线程设置
22             if (t.isDaemon())
23                 t.setDaemon(false);
24             // 设置默认优先级
25             if (t.getPriority() != Thread.NORM_PRIORITY)
26                 t.setPriority(Thread.NORM_PRIORITY);
27             return t;
28         }
29     }

DefaultThreadFactory 是默认的线程工程,提供创建线程的方法。

PrivilegedThreadFactory继承自DefaultThreadFactory,区别在于线程执行的run方法指定了classLoader并受到权限的控制。

DelegatedExecutorService继承自AbstractExecutorService,是一个包装类,暴露ExecutorService的方法。

DelegatedScheduledExecutorService继承自DelegatedExecutorService,实现了 ScheduledExecutorService接口。它也是一个包装类,公开ScheduledExecutorService方法。

时间: 10-20

Java Executor 框架的相关文章

[转]Java Executor框架和线程池笔记

Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭,可以简化并发编程的操作.因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一

Java Executor 框架学习总结

大多数并发都是通过任务执行的方式来实现的.一般有两种方式执行任务:串行和并行. class SingleThreadWebServer { public static void main(String[] args) throws Exception { ServerSocket socket = new ServerSocket(80); while(true) { Socket conn = socket.accept(); handleRequest(conn); } } } class

Java Executor 框架的实例详解

大多数并发都是通过任务执行的方式来实现的. 一般有两种方式执行任务:串行和并行. class SingleThreadWebServer {  public static void main(String[] args) throws Exception {   ServerSocket socket = new ServerSocket(80);   while(true) {    Socket conn = socket.accept();    handleRequest(conn);

Java多线程框架Executor详解

原文链接  http://www.imooc.com/article/14377 为什么引入Executor线程池框架new Thread()的缺点 每次new Thread()耗费性能调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪.不利于扩展,比如如定时执行.定期执行.线程中断 采用线程池的优点 重用存在的线程,减少对象创建.消亡的开销,性能佳可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争

JAVA 1.5 并发之 Executor框架 (二)execute VS submit

http://www.cnblogs.com/rockman12352/p/3788688.html 上一篇对于整体框架讲了很多东西,但是具体在使用时有一些细节并没有说出来 首先是执行任务 execute(); 执行任务,返回空,相当于 new Thread(task).start(); submit();   执行任务,但是会返回一个future<T>,就是计算好的结果,如果没有计算好则会阻塞,还有一个好处是可以管理exception public static void main(Stri

Java并发和多线程(二)Executor框架

Executor框架 1.Task?Thread? 很多人在学习多线程这部分知识的时候,容易搞混两个概念:任务(task)和线程(thread). 并发编程可以使我们的程序可以划分为多个分离的.独立运行的任务.而这些任务具体得由线程来驱动.Java中,Thread类自身不执行任何操作,它只是驱动赋予它的任务,任务由Runnable接口提供. 2.executor Executor是个简单的接口,但它却提供了一种标准的方法将任务的提交过程与任务的执行过程解耦开来,从而无须太大困难就可以为某种类型的

Java并发(基础知识)—— Executor框架及线程池

在Java并发(基础知识)—— 创建.运行以及停止一个线程中讲解了两种创建线程的方式:直接继承Thread类以及实现Runnable接口并赋给Thread,这两种创建线程的方式在线程比较少的时候是没有问题的,但是当需要创建大量线程时就会出现问题,因为这种使用方法把线程创建语句随意地散落在代码中,无法统一管理线程,我们将无法管理创建线程的数量,而过量的线程创建将直接使系统崩溃. 从高内聚角度讲,我们应该创建一个统一的创建以及运行接口,为我们管理这些线程,这个统一的创建与运行接口就是JDK 5的Ex

Java并发编程系列之十五:Executor框架

Java使用线程完成异步任务是很普遍的事,而线程的创建与销毁需要一定的开销,如果每个任务都需要创建一个线程将会消耗大量的计算资源,JDK 5之后把工作单元和执行机制区分开了,工作单元包括Runnable和Callable,而执行机制则由Executor框架提供.Executor框架为线程的启动.执行和关闭提供了便利,底层使用线程池实现.使用Executor框架管理线程的好处在于简化管理.提高效率,还能避免this逃逸问题--是指不完整的对象被线程调用. Executor框架使用了两级调度模型进行

Java多线程—Executor框架概述

1. 任务Task相关的接口与类 1.1 Runnable 表示一个可被执行的命令,通常用于在不同线程中执行任务. package java.lang; public interface Runnable { public void run(); } 1.2 Callable<V> 表示一个有返回结果的任务 package java.util.concurrent; public interface Callable<V> { V call() throws Exception;