类结构图:
ExecutorService的创建
ExecutorService的创建
第一种方式使用工厂类 Executors
它们均为大多数使用场景预定义了设置
1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
第二种方式,直接创建.
直接创建类 ThreadPoolExecutor, ScheduledThreadPoolExecutor的实例. 与工厂类创建的ExecutorService不同, 直接创建时所有策略需要自己配置,
ExecutorService threadPoolOrigin = new ThreadPoolExecutor(2,2,100,TimeUnit.DAYS,threadPoolQueue);
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(...);
其中ThreadPoolExecutor参数如下
- corePoolSize:线程池维护线程的最少数量
- maximumPoolSize:线程池维护线程的最大数量
- keepAliveTime: 线程池维护线程所允许的空闲时间
- unit: 线程池维护线程所允许的空闲时间的单位
- workQueue: 线程池所使用的缓冲队列
- handler: 线程池对拒绝任务的处理策略
具体线程的分配方式是,当一个任务被添加到线程池:
1. 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
2. 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
3. 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
4. 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
(也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。)
5. 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。
注:
核心线程最初只是在新任务到达时才被ThreadPoolExecutor创建和启动的,
但是也可以手动调用方法 prestartCoreThread() 或 prestartAllCoreThreads()来的提前启动核心线程。
ExecutorService的执行
1. execute(Runnable)
2. submit(Runnable)
3. submit(Callable)
4. invokeAny(...)
5. invokeAll(...)
execute(Runnable):
这个方法接收一个Runnable实例,并且异步的执行,请看下面的实例
submit(Runnable):
通过返回的Future对象,我们可以检查提交的任务是否执行完毕,请看下面执行的例子:
submit(Callable):
接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,而Runnable接口中的run()方法是void的,没有返回值。
invokeAny(…);
方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果
invokeAll(…)
invokeAll(…)与 invokeAny(…)类似也是接收一个Callable集合,但是前者执行之后会返回一个Future的List,其中对应着每个Callable任务执行后的Future对象。
所有代码如下:
// ExecutorService threadPool = Executors.newFixedThreadPool(2);
ExecutorService threadPool = Executors.newCachedThreadPool();
// ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(" execute 异步任务");
}
});
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println(" submit 任务");
}
});
Set<Callable<String>> callables = new HashSet<>();
callables.add(new Callable<String>() {
@Override
public String call() throws Exception {
return "Task1: "+ Thread.currentThread().getName();
}
});
callables.add(new Callable<String>() {
@Override
public String call() throws Exception {
return "Task2: "+ Thread.currentThread().getName();
}
});
callables.add(new Callable<String>() {
@Override
public String call() throws Exception {
return "Task3 "+ Thread.currentThread().getName();
}
});
String strResult= threadPool.invokeAny(callables);
System.out.println("invokeAny => "+strResult);
List<Future<String >> lstFutures = threadPool.invokeAll(callables);
for (Future<String> futurn :
lstFutures) {
System.out.println("future.get=> "+futurn.get());
}
System.out.println("invokeAll => "+strResult);
threadPool.shutdown();
ExecutorService的关闭
当我们使用完成ExecutorService之后应该关闭它,否则在JVM中线程会一直处于运行状态,
如果要关闭ExecutorService中执行的线程,我们可以调用ExecutorService.shutdown()方法。在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。
如果我们想立即关闭ExecutorService,我们可以调用ExecutorService.shutdownNow()方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。
Demo:
第一阶段调用 shutdown 拒绝传入任务,然后等60秒后,任务还没执行完成,就调用 shutdownNow(如有必要)取消所有遗留的任务:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
一些方法
boolean isShutdown()
如果此执行程序已关闭,则返回 true。
boolean isTerminated()
如果关闭后所有任务都已完成,则返回 true。注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
boolean awaitTermination(long timeout,TimeUnit unit) throws InterruptedException
等待(阻塞)直到关闭或最长等待时间或发生中断
参数:
timeout - 最长等待时间
unit - timeout 参数的时间单位
返回:
如果此执行程序终止,则返回 true;如果终止前超时期满,则返回 false
抛出:
InterruptedException - 如果等待时发生中断