多线程之Executor框架

来源:互联网 发布:广东动易软件 编辑:程序博客网 时间:2024/06/05 11:30

Executor框架是指JAVA 5中引入的java.util.concurrent包中的一系列功能类。包括了Executor,Executors,ExecutorService,AbstractExecutorService,Future,Callable,Runnable等。如下图:


一:Executor

Executor作为顶层接口,只提供了一个执行任务的方法。

<span style="font-size:14px;">void execute(Runnable command)</span>

二:ExecutorService

ExecutorService扩展了Executor并添加了Executor声明周期管理的方法。一个Executor的生命周期有三种状态,运
行(Running),关闭(Shutdown),终止(Terminate)。当Executor创建时处于运行状态,当调用
ExecutorService.shutdown()后,处于关闭状态,当Executor中所有的线程执行结束后,Executor处于终止状态。
ExecutorService中的主要方法:

1.  void shutdown()

调用该方法后,Executor处于关闭状态,不再接受新任务,如果此时还往Executor中添加任务,则抛类似与下面的异
常: java.util.concurrent.RejectedExecutionException。但允许执行之前提交但在等待队列中尚未执行的的任务,待所有的任务执行完成后,Executor处于终止状态。

2.  List<Runnable>  shutdownNow()

与shutdown功能类似,区别在于调用shutdownNow方法会尝试去停止正在执行的任务(但并不保证一定会立即停
止),并且返回调用该方法之前之前提交的尚未执行的任务列表。

3.  boolean isShutdown()

判断Executor是否关闭,当调用Executor.shutdown()或shutdownNow()后,该方法返回true。

4.  boolean isTerminated()

判断Executor是否终止,当调用Executor.shutdown()或shutdownNow(),待所有线程执行完成后,Executor处于终止
状态,调用该方法返回true。

5. boolean awaitTermination(long timeout, TimeUnit unit)   throws InterruptedException;

判断Executor在指定的时间内是否终止,如果超时则默认为未终止。timeout指定时间,unit指定时间单位。

6. <T> Future<T> submit(Callable<T> task)

向Executor中提交一个任务执行,任务实现Callable接口,并异步返回任务的执行结果Future<T>

7. <T> Future<T> submit(Runnable task, T result)

向Executor中提交一个任务执行,task为实现Runable接口的任务, resule指定任务的执行结果类型,并返回任务的

执行结果Future<T>

8. Future<?> submit(Runnable task)

向Executor中提交一个任务执行,默认的返回结果类型为Void

9. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)  throws

InterruptedException;

向Executor中提交一系列任务,全部调用执行,并返回与每个任务对应的Future,将执行结果返回到一个List列表
中。也就是说,任务彼此之间不会相互影响,可以通过future跟踪每一个任务的执行情况

10. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,  long timeout, 
TimeUnit unit)   throws InterruptedException

功能和上面的类似,只不过指定了一定的时间内获取结果,如果在指定的时间内没有执行完,则抛出
TimeoutExecption,中止任务线程。

11. <T> T invokeAny(Collection<? extends Callable<T>> tasks)   throws InterruptedException, ExecutionException;

invokeAny()返回最先正常完成(without throwing exception)的任务直接结果;一旦有任务正常完成或者调用出现异常,线程池都会终止正在运行或等待运行(tasks that have not completed are cancelled)的任务。

12. <T> T invokeAny(Collection<? extends Callable<T>> tasks,  long timeout, TimeUnit unit)   throws InterruptedException, ExecutionException, TimeoutException;

与上面的功能类似,不过也指定了在一定的时间内,如果在指定的时间内没有获取到结果,则抛TimeoutExecption,中止任务线程。

三:ThreadPoolExecutor

ThreadPoolExecutor是各个线程池的底层实现。关于这个类的详细介绍请参考:多线程之ThreadPoolExecutor。

四:Executors

Executors是一个工具类,提供了很多方法:创建线程池,创建Callable,创建ThreadFactory等。

Executors的主要方法:

1. public static ExecutorService newFixedThreadPool(int nThreads) 

创建一个线程数固定的线程池(ExecutorService)

<span style="font-size:14px;">public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());   }</span>

2. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)

功能与newFixedThreadPool()相同,区别在于线程有指定的线程工厂类创建

<span style="font-size:14px;">public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>(),                                      threadFactory);    }</span>

3. public static ExecutorService newSingleThreadExecutor() 

创建只拥有一个线程的线程池

<span style="font-size:14px;">public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }</span>

4. public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)

功能与newSingleThreadExecutor()相同,区别在于线程有指定的线程工厂类创建

<span style="font-size:14px;">public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>(),                                    threadFactory));    }</span>

5. public static ExecutorService newCachedThreadPool() 

创建线程数可动态调整的线程池,线程的空闲时间为60s,超过60s则回收该线程,无上限。

<span style="font-size:14px;">public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }</span>

6. public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)

功能与newCachedThreadPool()相同,区别在于线程有指定的线程工厂类创建

<span style="font-size:14px;">public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>(),                                      threadFactory);    }</span>

7. public static ScheduledExecutorService newSingleThreadScheduledExecutor()

创建只有一个线程的定时任务线程池,可定时执行任务

<span style="font-size:14px;">public static ScheduledExecutorService newSingleThreadScheduledExecutor() {        return new DelegatedScheduledExecutorService            (new ScheduledThreadPoolExecutor(1));    }</span>

8. public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

功能与newSingleThreadScheduledExecutor()相同,区别在于线程有指定的线程工厂类创建

<span style="font-size:14px;">public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {        return new DelegatedScheduledExecutorService            (new ScheduledThreadPoolExecutor(1, threadFactory));    }</span>

9.  public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个指定线程数的定时任务线程池,详细介绍参考章节:多线程之ScheduledExecutorService

<span style="font-size:14px;">public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);    }</span>

10. public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) 

功能与newScheduledThreadPool()相同,区别在于线程有指定的线程工厂类创建

<span style="font-size:14px;">public static ScheduledExecutorService newScheduledThreadPool(            int corePoolSize, ThreadFactory threadFactory) {        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);    }</span>

11. public static ThreadFactory defaultThreadFactory() 

返回一个默认的线程工厂类

<span style="font-size:14px;">public static ThreadFactory defaultThreadFactory() {        return new DefaultThreadFactory();    }</span>
DefaultThreadFactory类源码:

<span style="font-size:14px;">static class DefaultThreadFactory implements ThreadFactory {        private static final AtomicInteger poolNumber = new AtomicInteger(1);        private final ThreadGroup group;        private final AtomicInteger threadNumber = new AtomicInteger(1);        private final String namePrefix;        DefaultThreadFactory() {            SecurityManager s = System.getSecurityManager();            group = (s != null) ? s.getThreadGroup() :                                  Thread.currentThread().getThreadGroup();            namePrefix = "pool-" +                          poolNumber.getAndIncrement() +                         "-thread-";        }        public Thread newThread(Runnable r) {            Thread t = new Thread(group, r,                                  namePrefix + threadNumber.getAndIncrement(),                                  0);            if (t.isDaemon())                t.setDaemon(false);            if (t.getPriority() != Thread.NORM_PRIORITY)                t.setPriority(Thread.NORM_PRIORITY);            return t;        }    }</span>

12. public static <T> Callable<T> callable(Runnable task, T result)

由Runnable接口和执行结果的返回值类型创建一个Callable类返回

13. public static Callable<Object> callable(Runnable task)

有Runnable接口和默认的类型Void创建一个Callable类返回

五:线程池使用

任务类:
<span style="font-size:14px;">public class Task implements Runnable {private String name;int count = 0;public Task(String name) {this.name = name;}@Overridepublic void run() {while (count < 4) {count++;System.out.println(Thread.currentThread().getName() + "执行任务" + name+ "中。。。");try {Thread.sleep(1000 * 1);} catch (InterruptedException e) {e.printStackTrace();}}}}</span>

线程工厂类
<span style="font-size:14px;">public class WorkThreadFactory implements ThreadFactory{private static AtomicInteger count = new AtomicInteger(0);@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "线程"+ count.addAndGet(1));}}</span>

1. CacheThreadPool使用

主程序:
<span style="font-size:14px;">public class MainThread {private static WorkThreadFactory factory = new WorkThreadFactory();//线程工厂private static ExecutorService cacheThreadPool = Executors.newCachedThreadPool(factory);private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2, factory);private static ExecutorService singleExecutor = Executors.newSingleThreadExecutor(factory);private static ScheduledExecutorService sheduleExecutor = Executors.newScheduledThreadPool(2, factory);private static ScheduledExecutorService singleThreadscheduleExecutor = Executors.newSingleThreadScheduledExecutor(factory); public static void main(String[] args) {for(int i=0; i<3; i++){cacheThreadPool.execute(new Task(String.valueOf(i)));}}}</span>

运行结果:

线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。

从执行结果可以看出,这3个任务有3个线程在执行。

2. FixedThreadPool使用

依旧使用上面的程序,只是更换下线程池

<span style="font-size:14px;">public static void main(String[] args) {for(int i=0; i<3; i++){fixedThreadPool.execute(new Task(String.valueOf(i)));}}</span>

运行结果:

线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。


从运行结果可知,虽然有3个任务要运行,但是只有2个线程在执行这两个任务,因为配置该线程时就配置了该线程池线程的个数为固定2个。

3. SingleExecutor的使用

依旧使用上面的程序,只是更换下线程池

<span style="font-size:14px;">public static void main(String[] args) {for(int i=0; i<3; i++){singleExecutor.execute(new Task(String.valueOf(i)));}}</span>
运行结果:

线程1执行任务0中。。。
线程1执行任务0中。。。
线程1执行任务0中。。。
线程1执行任务0中。。。
线程1执行任务1中。。。
线程1执行任务1中。。。
线程1执行任务1中。。。
线程1执行任务1中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。
线程1执行任务2中。。。

从运行结果可知,只有一个线程在执行所有的任务。

4. ScheduledExecutorService的使用

请参考章节:多线程之ScheduledExecutorService

5. SingleScheduledExecutorService的使用

请参考章节:多线程之ScheduledExecutorService

六:ExecutorService的shutdown()与shutdownNow()

在本文中的第二部分已经讲到过shutdown()与shutdownNow()的区别,下面主要是从实例角度来分析下,依旧使用上面的程序,用FixedThreadPool线程池

1. 用shutdown()停止

public static void main(String[] args) {for(int i=0; i<3; i++){fixedThreadPool.execute(new Task(String.valueOf(i)));}if(!fixedThreadPool.isShutdown()){System.out.println("++++++++线程池处于运行状态+++++++++++++++++");}fixedThreadPool.shutdown();while(!fixedThreadPool.isShutdown()){}System.out.println("********线程池处于关闭状态****************");while(!fixedThreadPool.isTerminated()){}System.out.println("=========线程池处于终止状态===============");}

运行结果:

++++++++线程池处于运行状态+++++++++++++++++
********线程池处于关闭状态****************
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务2中。。。
线程2执行任务2中。。。
线程2执行任务2中。。。
线程2执行任务2中。。。
=========线程池处于终止状态===============

从运行结果可看出,当ExecutorService.shutdown被调用后,ExecutorService就处于关闭状态,但是当前正在运行的2个任务并没有被中止,而此时任务2应该是在等待执行的队列中,因为配的线程池为FixedThreadPool,大小为2,并发同时只能执行两个任务。在执行完任务0,任务1之后,任务2也被执行了,说明ExecutorService虽然被shutdown了,但是ExecutorService依然会执行已经被提交了但处于等待执行队列中的任务。

2. 用shutdownNow()停止

<span style="font-family:System;">public static void main(String[] args) {for(int i=0; i<3; i++){fixedThreadPool.execute(new Task(String.valueOf(i)));}if(!fixedThreadPool.isShutdown()){System.out.println("++++++++线程池处于运行状态+++++++++++++++++");}fixedThreadPool.shutdownNow();//改换成shutdownNow()System.out.println("********线程池处于关闭状态****************");while(!fixedThreadPool.isTerminated()){}System.out.println("=========线程池处于终止状态===============");}}</span>

运行结果:

++++++++线程池处于运行状态+++++++++++++++++
********线程池处于关闭状态****************
线程1执行任务0中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
线程2执行任务1中。。。
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.test.executor.Task.run(Task.java:26)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.test.executor.Task.run(Task.java:26)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
线程1执行任务0中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程2执行任务1中。。。
=========线程池处于终止状态===============

从运行结果可看出,当ExecutorService.shutdownNow被调用后,ExecutorService就处于关闭状态,但是当前正在运行的2个任务并没有被中止,而此时任务2也是在等待执行的队列中,在执行完任务0,任务1之后,任务2没被执行就结束了,说明ExecutorService被shutdownNow()后,ExecutorService不会再执行之前被提交了但处于等待执行队列中的任务。

3. 用shutdown()停止后继续添加任务
<span style="white-space:pre"></span>public static void main(String[] args) {for(int i=0; i<3; i++){fixedThreadPool.execute(new Task(String.valueOf(i)));}if(!fixedThreadPool.isShutdown()){System.out.println("++++++++线程池处于运行状态+++++++++++++++++");}fixedThreadPool.shutdown();for(int i=0; i<3; i++){//继续添加任务fixedThreadPool.execute(new Task(String.valueOf(i)));}System.out.println("********线程池处于关闭状态****************");while(!fixedThreadPool.isTerminated()){}System.out.println("=========线程池处于终止状态===============");}

运行结果:

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task cn.test.executor.Task@4aad8dbc rejected from java.util.concurrent.ThreadPoolExecutor@483457f1[Shutting down, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
at cn.test.executor.MainThread.main(MainThread.java:36)
....

从运行结果中可看出,当ExecutorService调用shutdown之后,继续往ExecutorSevice中添加任务就会报异常:RejectedExecutionException

4. 用shutdownNow()停止后继续添加任务

结果与测试3一样

七:ExecutorService的invokeAny()与invokeAll()

在本文中的第二部分也讲到了invokeAny与invokeAll()的作用,现在主要将下这两个方法的用法。主要是参考了网上一博友的文章:ExecutorServer中invokeAny与invokeAll的使用剖析。

<span style="font-family:System;font-size:10px;">public class SleepSecondsCallable implements Callable<String>{private String name;private int seconds;public SleepSecondsCallable(String name, int seconds){this.name = name;this.seconds = seconds;}public String call() throws Exception{System.out.println(name + ",begin to execute");try{TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e){System.out.println(name + " was disturbed during sleeping.");e.printStackTrace();return name + "_SleepSecondsCallable_failed";}System.out.println(name + ",success to execute");return name + "_SleepSecondsCallable_succes";}}</span><span style="font-size:18px;font-family: FangSong_GB2312;"></span>
这是一个通过睡眠来模拟的耗时任务,该任务是可中断/可终止的任务,能够响应中断请求。
<span style="font-family:System;font-size:10px;">public class ExceptionCallable implements Callable<String> {private String name = null;public ExceptionCallable() {}public ExceptionCallable(String name) {this.name = name;}@Overridepublic String call() throws Exception {System.out.println("begin to ExceptionCallable.");System.out.println(name.length());System.out.println("end to ExceptionCallable.");return name;}}</span>
这是一个可能会在执行过程中,抛出空指针异常的任务。
<span style="font-family:System;font-size:10px;">public class RandomTenCharsTask implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("RandomTenCharsTask begin to execute...");StringBuffer content = new StringBuffer();String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();for (int i = 0; i < 10; i++) {int number = random.nextInt(base.length());content.append(base.charAt(number));}System.out.println("RandomTenCharsTask complete.result=" + content);return content.toString();}}</span>
这是一个正常的短时的任务,产生10个随机字符组成的字符串。

1.测试invokeAny()

第一种情况,向线程池提交2个耗时任务SleepSecondsCallable
<span style="font-family:System;font-size:10px;">/** * 提交的任务集合,一旦有1个任务正常完成(没有抛出异常),会终止其他未完成的任务 */public static void invokeAny1() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(3);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new SleepSecondsCallable("t1", 2));tasks.add(new SleepSecondsCallable("t2", 1));String result = executorService.invokeAny(tasks);System.out.println("result=" + result);executorService.shutdown();}</span>
程序的执行结果是:返回t2线程的执行结果t2_SleepSecondsCallable_succes,同时t1抛出java.lang.InterruptedException: sleep interrupted。
也就说:一旦有1个任务正常完成(执行过程中没有抛异常),线程池会终止其他未完成的任务

第二种情况,向线程池提交3个异常任务ExceptionCallable
<span style="font-family:System;font-size:10px;">/** * 没有1个正常完成的任务,invokeAny()方法抛出ExecutionException,封装了任务中元素的异常 *  */public static void invokeAny2() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(3);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable("a"));String result = executorService.invokeAny(tasks);System.out.println("result=" + result);executorService.shutdown();}</span>
程序执行结果是:调用invokeAny()报错 java.util.concurrent.ExecutionException: java.lang.NullPointerException。
也就是说:如果提交的任务列表中,没有1个正常完成的任务,那么调用invokeAny会抛异常,究竟抛的是哪儿个任务的异常,无关紧要

第三种情况:先提交3个异常任务,再提交1个正常的耗时任务

<span style="font-family:System;font-size:10px;">/** * 有异常的任务,有正常的任务,invokeAny()不会抛异常,返回最先正常完成的任务 */public static void invokeAny3() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(3);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new SleepSecondsCallable("t1", 2));String result = executorService.invokeAny(tasks);System.out.println("result=" + result);executorService.shutdown();}</span>
程序执行结果是:不会抛出任何异常,打印出t2任务的返回结果。也就是说:invokeAny()和任务的提交顺序无关,只是返回最早正常执行完成的任务

第四种情况,测试下使用限时版本的invokeAny(),主要功能与不限时版本的差别不大
<span style="font-family:System;font-size:10px;">/** * 还没有到超时之前,所以的任务都已经异常完成,抛出ExecutionException<br> * 如果超时前满,还没有没有完成的任务,抛TimeoutException */public static void invokeAny4() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(3);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());tasks.add(new ExceptionCallable());String result = executorService.invokeAny(tasks, 2, TimeUnit.SECONDS);System.out.println("result=" + result);executorService.shutdown();}</span>
程序执行结果是:抛出ExecutionException。这个其实很合理,也很好理解。如果在超时之前,所有任务已经都是异常终止,那就没有必要在等下去了;如果超时之后,仍然有正在运行或等待运行的任务,那么会抛出TimeoutException。

最后我们来看下,JDK源码中ExecutorService.invokeAny的方法签名和注释
<span style="font-family:System;font-size:10px;">/**     * Executes the given tasks, returning the result     * of one that has completed successfully (i.e., without throwing     * an exception), if any do. Upon normal or exceptional return,     * tasks that have not completed are cancelled.     * The results of this method are undefined if the given     * collection is modified while this operation is in progress.     *     * @param tasks the collection of tasks     * @return the result returned by one of the tasks     * @throws InterruptedException if interrupted while waiting     * @throws NullPointerException if tasks or any of its elements     *         are <tt>null</tt>     * @throws IllegalArgumentException if tasks is empty     * @throws ExecutionException if no task successfully completes     * @throws RejectedExecutionException if tasks cannot be scheduled     *         for execution     */    <T> T invokeAny(Collection<? extends Callable<T>> tasks)        throws InterruptedException, ExecutionException;</span>
与我们测试结果一致,invokeAny()返回最先正常完成(without throwing exception)的任务直接结果;一旦有任务正常完成或者调用出现异常,线程池都会终止正在运行或等待运行(tasks that have not completed are cancelled)的任务。

2.测试invokeAll()

这个方法相对来说比较好理解,就是执行任务列表中的所有任务,并返回与每个任务对应的Futue。也就是说,任务彼此之间不会相互影响,可以通过future跟踪每一个任务的执行情况,比如是否被取消,是正常完成,还是异常完成,这主要使用Future类提供的API。
<span style="font-family:System;font-size:10px;">public static void invokeAll1() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(5);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new SleepSecondsCallable("t1", 2));tasks.add(new SleepSecondsCallable("t2", 2));tasks.add(new RandomTenCharsTask());tasks.add(new ExceptionCallable());// 调用该方法的线程会阻塞,直到tasks全部执行完成(正常完成/异常退出)List<Future<String>> results = executorService.invokeAll(tasks);// 任务列表中所有任务执行完毕,才能执行该语句System.out.println("wait for the result." + results.size());executorService.shutdown();for (Future<String> f : results) {// isCanceled=false,isDone=trueSystem.out.println("isCanceled=" + f.isCancelled() + ",isDone="+ f.isDone());// ExceptionCallable任务会报ExecutionExceptionSystem.out.println("task result=" + f.get());}}</span>
程序的执行结果和一些结论,已经直接写在代码注释里面了。invokeAll是一个阻塞方法,会等待任务列表中的所有任务都执行完成。不管任务是正常完成,还是异常终止,Future.isDone()始终返回true。通过Future.isCanceled()可以判断任务是否在执行的过程中被取消。通过Future.get()可以获取任务的返回结果,或者是任务在执行中抛出的异常。


第二种情况,测试限时版本的invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)

<span style="font-family:System;font-size:10px;">/** * 可以通过Future.isCanceled()判断任务是被取消,还是完成(正常/异常)<br> * Future.isDone()总是返回true,对于invokeAll()的调用者来说,没有啥用 */public static void invokeAll2() throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(5);List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new SleepSecondsCallable("t1", 2));tasks.add(new SleepSecondsCallable("t2", 2));tasks.add(new SleepSecondsCallable("t3", 3));tasks.add(new RandomTenCharsTask());List<Future<String>> results = executorService.invokeAll(tasks, 1, TimeUnit.SECONDS);System.out.println("wait for the result." + results.size());for (Future<String> f : results) {System.out.println("isCanceled=" + f.isCancelled() + ",isDone=" + f.isDone());System.out.println("task result=" + f.get());}executorService.shutdown();}</span>
执行结果是:

wait for the result.4
isCanceled=true,isDone=true
isCanceled=true,isDone=true
isCanceled=true,isDone=true
isCanceled=false,isDone=true

也就是说给定的超时期满,还没有完成的任务会被取消,即Future.isCancelled()返回true;在超时期之前,无论是正常完成还是异常终止的任务,Future.isCancelled()返回false。

第三种情况,测试在等待invokeAll执行完成之前,线程被中断。

<span style="font-family:System;font-size:10px;">/** * 如果线程在等待invokeAll()执行完成的时候,被中断,会抛出InterruptedException<br> * 此时线程池会终止没有完成的任务,这主要是为了减少资源的浪费. */public static void testInvokeAllWhenInterrupt() throws Exception {final ExecutorService executorService = Executors.newFixedThreadPool(5);// 调用invokeAll的线程Thread invokeAllThread = new Thread() {@Overridepublic void run() {List<Callable<String>> tasks = new ArrayList<Callable<String>>();tasks.add(new SleepSecondsCallable("t1", 2));tasks.add(new SleepSecondsCallable("t2", 2));tasks.add(new RandomTenCharsTask());// 调用线程会阻塞,直到tasks全部执行完成(正常完成/异常退出)try {List<Future<String>> results = executorService.invokeAll(tasks);System.out.println("wait for the result." + results.size());} catch (InterruptedException e) {System.out.println("I was wait,but my thread was interrupted.");e.printStackTrace();}}};invokeAllThread.start();Thread.sleep(200);invokeAllThread.interrupt();executorService.shutdown();}</span>
invokeAllThread 线程调用了ExecutorService.invokeAll(),在等待任务执行完成的时候,invokeAllThread被别的线程中断了。这个时候,ExecutorService.invokeAll()会抛出java.lang.InterruptedException,任务t1和t2都被终止抛出java.lang.InterruptedException: sleep interrupted。也就是说一旦ExecutorService.invokeAll()方法产生了异常,线程池中还没有完成的任务会被取消执行。











0 0
原创粉丝点击