Java中官方推荐的线程池有四种:线程池介绍参考:https://www.cnblogs.com/CarpenterLee/p/9558026.html;在jdk1.8加入了 ForkJoinPool的扩展,newWorkStrealingPool,能够合理的使用CPU对任务进行并行操作,适合用于耗时的操作
但是这几种线程池会造成OOM的问题;
1、阻塞队列是无界的,导致不停的往队列中加任务,最后导致溢出;
2、启用的线程数量 过多,例如newCachedThreadPool ,这种线程池的maxmumPoolSize是max_Integer 所以如果当前线程数大于core并且队列已满的情况下,就会创建新线程,如果aliveTime时间较长没有及时GC掉,最终导致溢出;
所以一般推荐使用 new ThreadPoolExecutor(int corePoolSize,int maxNumPoolSize,long keepAliveTime,TimeUnit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler policy)来进行自定义线程池;在这里先重点梳理一下线程池中的阻塞队列和拒绝策略:
阻塞队列有:
基于数组结构的: ArrayBlockingQueue :创建时要指定一个容量;
基于链表结构的: LinkedBlockingQueue、LinkedBlockingDeque 创建时可以指定容量,不指定则默认为一个无界队列;newFixedThreadPool、newSingleThreadPool、用的是这个无界的Queue
同步的: SynchronousQueue:容量为0,这种同步队列只有在有线程写入元素时,另一个线程才能通过poll获取到元素,否则返回null;简单来说这种队列将任务直接提交,而不维持队列,在自定义线程池中默认的队列;newCachedThreadPool用的是这个
混合的:DelayedWorkQueue:基于DelayQueue和PriorityQueue,是延迟的并且具有自然排序的阻塞队列;newScheduledThreadPool用这个。
PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现Comparable接口也可以提供Comparator来对队列中的元素进行比较,跟时间没有任何关系,仅仅是按照优先级取任务。
拒绝策略:
作用场景:在队列已满,并且线程数量达到了maxmumPoolSize的时候;
拒绝策略的接口是: RejectedExecutionHandler;ThreadPoolExecutor中提供了四个静态方法返回实现了该接口的对象:
AbortPolicy:抛出RejectedExecutionException异常
CallerRunsPolicy:直接由提交任务者来执行这个任务(一般是main线程);因此使用这种策略会导致主线程堵塞;容易导致故障
DiscardOldesPolicy:弹出队列中最年长的任务,尝试将要执行的任务加到队列中;
DiscardPolicy:忽略这个任务,不抛出异常
附一张很好的线程池工作流程图: