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