16-线程池

与数据库连接池类似,线程池在系统启动时即创建大量空闲的线程。程序将一个 Runnable 对象或 Callable 对象传给线程池,线程池就会启动一个线程来执行它们的 run() 或 call() 方法,当 run() 或 call() 方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个 Runnable 对象的 run() 或 call() 方法。

创建线程池

使用 Executors 工厂类来产生线程池,包含以下静态工厂方法来创建线程池:

  • newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。
  • newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数 nThreads 的线程池。
  • newSingleThreadExecutor():创建一个只有单线程的线程池,它相当于调用 newFixedThreadPool() 方法时传入参数为 1.
  • newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务。corePoolSize 指池中所保存的线程数,即使线程是空闲的也被保存在线程池内。
  • newSingleThreadScheduledExecutor():创建只有一个线程的线程池,它可以在指定延迟后执行线程任务。
  • ExecutorService newWorkStealingPool(int parallelism):创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争。
  • ExecutorService newWorkStealingPool():该方法是前一个方法的简化版本。如果当前机器有 4 个CPU,则目标并行级别设置为 4,也就是相当于为前一个方法传入 4 作为参数。

上面7个方法中的前三个返回一个 ExecutorService 对象,该对象代表一个线程池,它可以执行 Runnable 对象或 Callable 对象所代表的线程;而中间两个方法返回一个 ScheduledExecutorService 线程池,它是 ExecutorService 的子类,它可以在指定延迟后执行线程任务;最后两个方法则是 Java8 新增的,可以充分利用多 CPU 并行的能力,这个两个方法生成的 work stealing 池,都相当于后台线程池。

ExecutorService

ExecutorService 代表尽快执行线程的线程池(意味着只要线程池中有空闲的线程,就立即执行线程任务),程序只要将一个 Runnable 对象或 Callable 对象提交给该线程池,该线程池就会尽快执行该任务。ExecutorService 提供了如下三个方法:

  • Future<?> submit(Runnable task):将一个 Runnable 对象提交给指定的线程池,线程池将在有空闲线程时执行 Runnable 对象代笔的任务。其中 Future 对象代表 Runnable 任务的返回值。可以调用 Future 的 isDone()、isCancelled() 方法来获得 Runnable 对象的执行状态。
  • Future submit(Runnable task,T result):将一个 Runnable 对象提交给指定的线程,线程池将在有空闲线程时执行 Runnable 对象代表的任务。其中 result 显式指定线程执行结束后的返回值,所以 Future 对象将在 run() 方法执行结束后返回 result。
  • Future submit(Callable task):将一个 Callable 对象提交给指定的线程池,线程池将在有空闲线程时执行 Callable 对象代表的任务。

ScheduledExecutorService

ScheduledExecutorService 代表可在指定延迟后或周期性地执行线程任务的线程池,它提供了如下 4 个方法:

  • ScheduledFuture schedule(Callable callable,long delay,TimeUnit unit):指定 callable 任务将在 delay 延迟后执行。
  • ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unie):指定 command 任务将在 delay 延迟后执行。
  • ScheduledFuture<?> schedulAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):指定 command 任务将在 delay 延迟后执行,而且以设定频率重复执行。在 initialDelay 后开始执行,依次在 initialDelay+period、initialDelay+2*period…..处重复执行,以此类推。
  • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit):创建并执行一个在给定延迟后首次启用的定期操作,随后在每一次执行终止和下一次执行开始之间都存在给定的延迟。如果任务在任一次执行时遇到异常,就会取消后续执行;否则,只能通过程序来显式取消或终止该任务。

用完一个线程池后,应该调用该线程池的 shutdown() 方法,来启动该线程池的关闭序列,此时线程池不再接收新任务,但会将以前提交的任务执行完成后所有线程死亡。也可以调用线程池的 shutdownNow() 方法来立即线程池。

使用线程池

使用线程池来执行线程任务的步骤如下:

  1. 调用 Executors 工具类的静态工厂方法来创建一个 ExecutorService 对象,该对象代表一个线程池。
  2. 创建 Runnable 实现类或 Callable 实现类的实例,在 run() 或 call() 方法中编写执行任务。
  3. 调用 ExecutorService 对象的 submit() 方法来提交 Runnable 实例或 Callable 实例。
  4. 当不想提交任何任务似乎,调用 ExecutorService 对象的 shutdown() 方法来关闭线程池。