Executor框架、Executors、ExecutorService及CompletionService
Executor:java.util.concurrent提供了一种灵活的线程池 实现作为Executor的一部分。Executor虽是个简单的接口,但能支持多种不同类型的任务执行策略。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
Executor:一个接口,只有一个executor方法,该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类,一般来说,Runnable任务开辟在新线程中的使用方法为:new Thread(new RunnableTask())).start(),但在Executor中,可以使用Executor而不用显示地创建线程:executor.execute(new RunnableTask()); // 异步执行
ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法(ExecutorService的生命周期三个状态:运行、关闭、终止),返回 Future 对象,以及可跟踪一个或多个异步任务执行状况返回Future的方法;可以调用shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。shutdownNow方法将执行粗暴的关闭过程:将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。因此我们一般用该接口来实现和管理多线程。
ExecutorService.submit() 方法返回的 Future 对象,可以调用isDone()方法查询Future是否已经完成。当任务完成时,它具有一个结果,你可以调用get()方法来获取该结果。你也可以不用isDone()进行检查就直接调用get()获取结果,在这种情况下,get()将阻塞,直至结果准备就绪,还可以取消任务的执行。Future 提供了 cancel() 方法用来取消执行 pending 中的任务。
public interface ExecutorService extends Executor {
//生命周期管理方法
void shutdown();
List<Runnbale> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
//其他部分方法
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
}
Executors:提供线程池的操作。通过调用Executos中的静态工厂方法之一来创建一个线程池:
newFixedThreadPool:将创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这是线程池的规模将不再变化(如果某个线程由于发生了未预期的Exception而结束,那么线程池会补充一个新的线程)。
newCachedThreadPool:将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在任何限制。
newSingleThreadExecutor:一个单线程的Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来替代。newSingleThreadExecutor能确保依照任务在队列中的顺序来串行执行。
newScheduledThreadPool:创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
Executor 和 ExecutorService 主要的区别:
1.ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口
2.Executor 接口定义了 execute()方法用来接收一个Runnable接口的对象,而 ExecutorService 接口中的 submit()方法可以接受Runnable和Callable接口的对象。
3. Executor 中的 execute() 方法不返回任何结果,而 ExecutorService 中的 submit()方法可以通过一个 Future 对象返回运算结果。
4.除了允许客户端提交一个任务,ExecutorService 还提供用来控制线程池的方法。比如:调用 shutDown() 方法终止线程池。
CompletionService:异步非阻塞获取并行任务执行结果。CompletionService将Executor(异步线程)和BlockingQueue(队列)的功能融合在一起,可以将Callable任务提交给它来执行,然后使用类似于队列操作的take和poll等方法来获得已完成的结果。通过该类可以立即获取每个线程的结果。
//初始化线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
//创建线程
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool);
for (int j = 1; j <= 5; j++) {
final int index = j;
completionService.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
//第三个线程睡眠等待
if (index == 3) {
java.lang.Thread.sleep(3000l);
}
return index;
}
});
}
threadPool.shutdown();
for (int i = 0; i < 5; i++) {
try {
System.out.println("线程:"+completionService.take().get()+" 任务执行结束:");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
获取的结果是无序的,第三个睡眠线程始终最后结束,也证实了获取结果的方式是非阻塞的。如下:
线程:2 任务执行结束
线程:1 任务执行结束
线程:5 任务执行结束
线程:4 任务执行结束
线程:3 任务执行结束
文章参考:
https://blog.csdn.net/weixin_40304387/article/details/80508236
https://blog.csdn.net/woshilijiuyi/article/details/78970497