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
三: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;
}
@Override
public 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);
@Override
public 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>
运行结果:
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
线程2执行任务1中。。。
线程1执行任务0中。。。
线程3执行任务2中。。。
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()
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中。。。
=========线程池处于终止状态===============
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中。。。
=========线程池处于终止状态===============
<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("=========线程池处于终止状态===============");
}
运行结果:
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)
4. 用shutdownNow()停止后继续添加任务
七:ExecutorService的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;
}
@Override
public 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> {
@Override
public 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()
<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>
<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>
第三种情况:先提交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()和任务的提交顺序无关,只是返回最早正常执行完成的任务。
<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。
<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=true
System.out.println("isCanceled=" + f.isCancelled() + ",isDone="
+ f.isDone());
// ExceptionCallable任务会报ExecutionException
System.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() {
@Override
public 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()方法产生了异常,线程池中还没有完成的任务会被取消执行。