Java 线程池细节补充

2020-11-15 0 By admin

一、固定数目的线程执行器

使用 Executors 类的 newFixedThreadPool() 方法可以创建固定数目的线程执行器,线程的数目可以由用户指定;也可以不指定,默认为当前处理器可以处理的最大线程数。
ExecutorService executor = Executors.newFixedThreadPool(4);
当提交到线程池的 Runnable 对象数大于执行器可以处理的线程数时,将有部分 Runnable 对象等待。

二、使用线程执行器处理有返回值的线程

有返回值的线程定义需要继承 Callable 接口,然后将线程交给执行器执行,提交线程需要使用 submit() 方法。

三、延迟执行、周期性执行的执行器

如果想在某一段时间之后执行线程操作,或者周期性地重复执行线程操作,则可以使用工厂类 Executors 的 newScheduledThreadPool() 方法或 newSingleThreadScheduledExecutor() 方法。

  1. newScheduledThreadPool() 方法使用给定数目的线程来调度执行任务;
  2. newSingleThreadExecutor() 方法在一个单独的线程中调度执行任务。
  3. 这两个方法都将返回一个 ScheduledExecutorService 线程池对象。

四、取消任务的执行

线程在执行的过程中,也可能因为各种各样的原因被取消执行,JDK 考虑到这种情况,提供了 Future 接口的 cancel() 方法,该方法可以取消线程的执行。

五、任务装载和结果处理的分离

当使用 Executor 处理并发任务时,通常会把 Callable 对象提交给 Executor 处理,在通过类 FutureTask 的 get() 方法获取结果。如果当前任务的结果还没有计算出来,线程将会阻塞在此处等待,即使后面的结果计算出来了,也不能处理。很显然,这会导致性能的下降。
CompletionService 接口整合了 Executor 和阻塞队列的功能,它的定义形式如下:

public interface CompletionService<V>

该接口提供了一种服务,该服务可以分离异步任务的产生和已完成任务的结果;可以通过 submit() 提交任务,通过 task() 方法取得已完成的任务的结果,并且按完成的先后顺序处理它们的结果。

六、管理被拒绝的任务

可以通过方法 shutdown() 关闭执行器,在调用该方法后,执行器将等待那些正在运行的或等待的任务的完成,然后才能真正地关闭执行器。关闭后的执行器将不再接收新的任务。
由于关闭执行器有一定的时间延迟,很可能在提交了关闭申请但还没有真正关闭执行器之前,新的任务被提交到该执行器,对于这样的任务,可以通过接口 RejectedExecutionHandler 来处理。