浅谈Java线程池原理

多线程可并发处理多个任务,提高计算机资源的利用率和工作效率,但不能来一个任务就开一个线程处理,因为创建、切换、销毁线程的开销不小,如果是处理短小任务的话,很有可能得不偿失,甚至造成系统崩溃。为了解决线程开销和,线程池的概念应运而生。
某一时刻的任务队列和线程池.png

J.U.C包中有三个关于线程池的接口,分别是:
(1)Executor: 运行新任务的简单接口,将任务提交和任务执行细节解耦。ThreadPoolExecutor实现了它;
(2)ExecutorService: 具备管理执行器和任务生命周期的方法,使提交任务机制更完善;
(3)ScheduledExecutorService: 支持Future和定期执行任务;
 

一、ThreadPoolExecutor的构造方法参数

(1)int corePoolSize: 该线程池中核心线程数最大值
(2)int maximumPoolSize: 该线程池中线程总数最大值
(3)long keepAliveTime: 非核心线程闲置超时时长
(4)TimeUnit unit: keepAliveTime的单位
核心线程是线程池必要维护的线程,如果可执行的任务数<=corePoolSize,那么空闲的核心线程只会被阻塞,等待新任务;当可执行任务数>核心线程数的时候,线程不够用了,在线程数<=maximumPoolSize && 线程状态的情况下,可以生成非核心线程处理任务。一旦处理完任务,过了keepAliveTime时候,非核心线程就会被销毁;
(5)BlockingQueue workQueue: 阻塞队列,维护着等待执行的Runnable任务对象。有不同类型:LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue、DelayQueue;
(6)ThreadFactory threadFactory(非必需): 创建线程的工厂类,可以指定某些参数配置,批量创建线程;
(7)RejectedExecutionHandler handler(非必需): 拒绝处理策略,有如下几种:
  1) AbortPolicy:直接抛出异常,这是默认策略
  2) CallerRunsPolicy:退回给调用者执行任务
  3) DiscardOldestPolicy:丢弃队列中靠最前的任务,并执行当前任务
  4)DiscardPolicy:直接丢弃任务
  5)实现RejectedExecutionHandler接口的自定义handler
 

二、ExecutorService和线程池状态

线程池状态转换.png (1)RUNNING:线程池创建之后即为RUNNING状态,表示可以接收任务; (2)SHUTDOWN:调用shutdown()之后就不能接收新任务了,但可以处理已经任务队列里、在线程池执行中的任务; (3)STOP:调用shutdownNow(),不会接收新任务,中断正在执行任务的线程,丢掉在任务队列里的任务; (4)TIDYING:所有的任务都已经终止了,任务数量为0,接着执行钩子函数terminated() (5)TERMINATED:线程池彻底终止