线程池与锁
第4章 线程池入门
4.1 ThreadPoolExecutor
ThreadPoolExecutor是应用最广的底层线程池类,它实现了Executor和ExecutorService接口。
4.1.1 创建线程池
下面创建一个线程池,通过调整线程池构造函数的参数来了解线程池的运行特性。把核心线程数设置为3,最大线程数设置为8,阻塞队列的容量设置为5。
(1)当要执行的任务数小于核心线程数时,直接启动与任务数相同的工作线程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lizYO2tW-1678433605839)(null)]
(2)当任务数量大于核心线程数时,超过核心线程数的任务会自动加入阻塞队列中,直到把阻塞队列装满。
(3)当任务数大于“最大线程数+阻塞队列容量”时,会抛出RejectedExecutionException(拒绝执行任务)异常。当前线程池的设置参数,最大容量是8+5=13,当任务数超过13时,都会被拒绝。
4.1.2 关闭线程池
调用ThreadPoolExecutor的shutdown()方法或shutdownNow()方法,可以关闭线程池。
调用shutdown()方法后,原来提交的任务会被有序执行,但是不会再接受新的任务。
shutdownNow()与shutdown()的主要区别是:shutdownNow()可以把已提交但是未执行的任务主动取消,并返回未执行的任务列表。
4.2 Executor接口
Executor接口中,只有一个execute()方法。它表明在将来某个时刻,执行一个给定的任务。这个任务可以在一个新线程中或线程池中执行,也可以在调用execute()方法的这个线程中执行。
执行器Executor把任务的提交和任务的运行进行了有机分解,从而实现了解耦。通常无须显示创建线程,如new Thread(new(RunnableTask())).start(),而是按照如下方式创建线程并执行任务:
4.3 ExecutorService接口
java.util.concurrent包中的ExecutorService接口继承了Executor接口。Executor接口只提供了任务的执行方法,为了解决执行服务对象的生命周期问题,ExecutorService添加了一些用于生命周期管理的方法,如终止任务、提交任务、跟踪任务返回结果等。
ExecutorService认为服务对象的生命期有3种状态:运行、关闭和终止。调用shutdown()方法可以有序关闭任务,调用sutdownNow()方法可以强制关闭未执行的任务,一旦所有的任务都执行完毕,ExecutorService会转入终止状态。
4.3.1 Callable返回任务执行结果
Callable和Runnable都是执行任务的接口,但是Runnable接口中的run()方法无返回结果,而Callable的call()方法可以返回执行结果。
同时Callable接口的call()方法允许抛出异常,而Runnable接口中的run()方法异常只能在内部消化(日志),不能抛给线程的调用者。
4.3.2 shutdown与shutdownNow
调用ExecutorService接口的shutdown()方法,启动有序关闭,其中先前提交的任务将仍然被执行,但是不会再接受任何新的任务。调用shutdownNow()方法,会尝试停止所有任务,包括正在执行的任务和等待处理的任务,这个方法会返回未执行的任务列表。
4.4 Executors工具箱
Executors工具箱为Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和Callable等提供了工厂方法或工具方法。
该类支持以下几种方法:
(1)创建并返回一个ExecutorService对象,推荐了几种常用线程池的配置方式。
(2)创建并返回一个ScheduledExecutorService对象