# 线程池
线程池的好处:
重用存在的线程,减少对象的创建/销毁的开销,性能更佳。
可有效控制最大并发线程数量,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞。
提供定时执行、定期执行、单线程、并发数控制等功能。
ThreadPoolExecutor 是 J.U.C 中提供的线程池类。
# 线程池的创建
创建线程池时(new ThreadPoolExecutor()
)会涉及到如下几个参数:
corePoolSize:线程池的核心线程数量。逻辑上,就是线程池中线程数量的下限。
maximumPoolSize:线程池最大线程数。逻辑上,就是线程池中线程数量的上限。
poolSize:线程池当前的线程数。它的值会在 corePoolSize 和 maximumPoolSize 之间。
workQueue:阻塞队列,存储待执行的任务。很重要,会对线程池运行过程产生重大影响。
keepAliveTime:线程没有任务执行时最多保持多久时间终止。
unit:keepAliveTime 的时间单位
threadFactory:线程工厂,用来创建线程
rejectHandler:当拒绝处理任务(例如线程池已满,不再接受新任务)时的策略
不过通常我们并非使用 new 的方式创建线程池。J.U.C 提供了 Executors
工具类,并提供了几个简化线程池创建的方法:
Executors.newSingleThreadExecutor()
创建一个单线程的线程池。该线程池中有且仅有一个工作线程(来处理任务),即,线程池中储于 Running 状态的线程数不能超过 1 。
当任务数超过 1 时,需要等待。
Executors.newFixThreadPool()
创建一个线程数目固定的线程池。对于添加到任务队列中的任务,如果线程池还有可用线程,那么就执行该任务。如果所有线程已被占用,那么任务的执行将会等到有线程执行完它手头的工作(任务)后才开始。
Executors.newScheduledThreadPool()
同上。还支持定时及周期性任务执行。
Executors.newCachedThreadPool()
创建一个可缓存线程。逻辑上就是 FixThreadPool 的【反面】。
该线程池一旦发现线程不够用就会创建新线程去执行新添加的任务,并且它会复用已有的线程。线程执行完任务后,如果存活期到期,到期时间内一直未被使用,那么线程池会销毁过期的线程。
# 线程池的状态
状态 | 说明 |
---|---|
Running | 线程池正在运行中 |
Shutdown | 关闭状态之一。这种状态下线程池不再接受新的任务,但是会将已接受的任务处理完。处理完后,线程池会自动进入 Tidying 状态。 |
Stop | 另一种关闭状态。这种状态下不再接受新的任务,并且会放弃已接受的而又未执行的任务。不仅如此,它还会取消正在执行中的任务。取消掉正在执行的任务后,线程池会自动进入 Tidying 状态。 |
Tidying | 这种状态下的线程池意味着不再具有任何功能。其中工作线程数量为 0 。 |
Terminated | 这种状态下线程池彻底停止,接下来就是 JVM 着手回收相关对象。 |
# 相关 API
方法 | 说明 |
---|---|
execute() | 提交任务,交给线程池执行。 |
submit() | 同上。能够返回执行结果。结合 Callable 和 Future 使用。 |
shutdown() | 关闭线程池,等待任务都执行完。即,线程池进入 Shutdown 状态。 |
shutdownNow() | 关闭线程池,不等待任务执行完。即,线程池进入 Stop 状态。 |
getTaskCount() | 返回线程池已执行和未执行任务总数。即,总共接收的任务数。 |
getCompletedTaskCount() | 返回线程中已完成的任务数。 |
getPoolSize() | 返回线程池当前的线程数量。 |
getActiveCount() | 返回线程池中正在执行任务的线程数量。 |