线程池的作用
1.提高效率,创建好一定数量的线程,等需要的时候,就从池中拿一个,比需要的时候再创建要快得多
2.方便管理线程,可以在启动程序时创建多个线程,需要的时候再分配,如果一起并发线程过多,那么,多的线程排队等候,避免了多次创建线程
线程池的参数
corePoolSize核心池的大小
核心池的大小,在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize
线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
keepAliveTime
表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize ,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize
unit
参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue
一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
PriorityBlockingQueue
拒绝策略
如果当前存货线程数以达到最大数量,还有新的任务被提交,直接采用拒绝策略处理
线程池的执行流程
1.提交一个任务,会在线程池中分配一个空闲线程,执行任务
2. 如果没有空闲线程,则会判断当前线程数是否少于核心线程数,如果小于,线程池会创建一个核心线程去处理任务
3. 如果大于核心线程数,则会判断队列数是否已满,
4. 如果队列未满,则将该线程任务放入工作队列,等待线程池从工作队列去除并执行
5. 如果已达到最大线程数,则直接采用拒绝策略处理
常用工作队列
阻塞工作队列
BlockingQueue
阻塞队列接口,实现机制是使用两条线程,允许两个线程同时操作队列,一个线程用于存储(生产者),一个线程用于取出(消费者)。当队列中没有数据的情况下,消费者端的所有线程都会被自动阻塞,直到有数据放入队列;当队列中数据写满时,生产者端的所有线程被自动阻塞。在保证并发安全的同时,提高了队列的存取效率。
ArrayBlockingQueue
是一个有界队列,基于数组实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,按照FIFO的方式排序;入队与出队的操作,使用同一个ReentrantLock来进行控制
LinkedBlockingQueue
是一个无界队列,基于单向链表结构,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE。入队与出队的操作,使用不同ReentrantLock来进行控制,所以LinkedBlockingQueue吞吐量通常要高于 ArrayBlockingQuene。
DelayedWorkQueue
是基于堆结构的延迟队列,基于数组实现,初始容量为16,leader线程用于获取堆顶元素(队列头部元素)。该队列根据指定的延迟时间从小到大排序,如果延迟时间相同,则根据插入到队列的先后排序。
PriorityBlockingQueue
是一个基于优先级的无界队列(优先级的判断通过构造函数传入的Compator或元素实现Comparable接口来决定)。
注意:PriorityBlockingQueue并不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者。因此使用的时候要特别注意,生产者生产数据的速度绝对不能快于消费者消费数据的速度,否则时间一长,会最终耗尽所有的可用堆内存空间。
案例:每个订单使用一个线程进行支付,支付时按照订单金额的优先级
SynchronousQueue(同步队列)
不存储元素的阻塞队列(内部没有保存元素的数据结构容器),每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。
CachedThreadPool线程池使用这个队列。
线程池状态
线程池状态分为:RUNNING , SHUTDOWN , STOP , TIDYING ,TERMINATED
RUNNING
运行状态,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0。该状态的线程池会接收新任务,并处理工作队列中的任务。
■ 调用线程池的shutdown()方法,可以切换到关闭状态;
■ 调用线程池的shutdownNow()方法,可以切换到停止状态;
SHUTDOWN
关闭状态,该状态的线程池不会接收新任务,但会处理工作队列中的任务;
■ 当工作队列为空时,并且线程池中执行的任务也为空时,线程池进入状态;
STOP
停止状态,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行 的任务;
■ 线程池中执行的任务为空,进入状态;
TIDYING
整理状态,该状态表明所有的任务已经运行终止,记录的任务数量为0;
■ terminated()执行完毕,进入TERMINATED状态;
TERMINATED
该状态表示线程池彻底终止