# 线程池

线程池的好处:

  • 重用存在的线程,减少对象的创建/销毁的开销,性能更佳。

  • 可有效控制最大并发线程数量,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞。

  • 提供定时执行、定期执行、单线程、并发数控制等功能。

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() 返回线程池中正在执行任务的线程数量。