什么是线程池
池化技术是一个常用技术,主要目的都是为了避免对象的频繁创建和销毁带来的额外性能损耗。
线程池的目的也是为了减少频繁的创建线程和销毁线程带来的性能损耗。通过利用线程池中已存在的线程去接收新的任务,可以减少创建和销毁带来的性能损耗。
这一个思想就类似于现在的共享单车,在你需要骑车的时候,你马路上随便找一辆空闲的的单车来骑,在你不需要的时候,那个单车又可以给别人来骑,这样子就大大的提升了一辆单车的使用率,变相的节约了资源。
一、线程池的7大参数
啪!的一下,很快阿,先亮源码,可以看到,线程池的构造函数有7个参数
①corePoolSize:线程池核心线程数量。
默认情况下,线程池中线程的数量如果 <= corePoolSize,那么即使这些线程处于空闲状态,那也不会被销毁。
②maximumPoolSize:线程池中最多可容纳的线程数量。当一个新任务交给线程池,如果此时线程池中有空闲的线程,就会直接执行,如果没有空闲的线程且当前线程池的线程数量小于corePoolSize,就会创建新的线程来执行任务,否则就会将该任务加入到阻塞队列中,如果阻塞队列满了,就会创建一个新线程,从阻塞队列头部取出一个任务来执行,并将新任务加入到阻塞队列末尾。如果当前线程池中线程的数量等于maximumPoolSize,就不会创建新线程,就会去执行拒绝策略。
③keepAliveTime:当线程池中线程的数量大于corePoolSize,并且某个线程的空闲时间超过了keepAliveTime,那么这个线程就会被销毁。
④unit:就是keepAliveTime时间的单位。
⑤workQueue:工作队列。当没有空闲的线程执行新任务时,该任务就会被放入工作队列中,等待执行。
有四种工作队列:
队列名称
作用
ArrayBlockingQueue
数组阻塞队列,根据FIFO排序,可以指定队列的大小,因为可以指定队列大小,所以可以防止内存溢出(OOM:Out Of Memory)
LinkedBlockingQueue
链表阻塞队列,根据FIFO排序,默认队列容量为Integer.MAX_VALUE,也可以自己指定容量,当未指定容量时可以理解为无限容量的队列,使用此队列时,maximumPoolSize就是摆设了,不起作用,因为队列容量太大了。此阻塞队列容易导致OOM
SynchronousQueue
同步队列,每次向该队列放入一个任务,必须要有空闲线程去领走,没有空闲线程就创建,创建不了就执行拒绝策略
PriorityBlockingQueue
带优先级的阻塞队列,前面三种队列都是规定好了排序顺序的,这个阻塞队列可以自定义容量也可以自定义排序,创建时可以传入Comparator自定义优先级
⑥threadFactory:线程工厂。可以用来给线程取名字等等
⑦handler:拒绝策略。当一个新任务交给线程池,如果此时线程池中有空闲的线程,就会直接执行,如果没有空闲的线程,就会将该任务加入到阻塞队列中,如果阻塞队列满了,就会创建一个新线程,从阻塞队列头部取出一个任务来执行,并将新任务加入到阻塞队列末尾。如果当前线程池中线程的数量等于maximumPoolSize,就不会创建新线程,就会去执行拒绝策略。
二、四个拒绝策略
①CallerRunsPolicy:调用者执行策略。就是调用者线程直接执行被拒绝任务的run方法,除非线程池已经被shutdown,shutdown的线程池不接受新任务。
②AbortPolicy:终止策略。就是不执行任务,并抛出RejectedExecutionException异常
③DiscardPolicy:抛弃策略。就是不执行任务,啥也不干。(对,就是这么懒,不讲武德)
④DiscardOldestPolicy:抛弃最老策略(这个翻译有点直接,只要能理解意思就好)。该策略会抛弃进入队列最早的那个任务,然后把该任务加入队列。