3.keepAliveTime:最⼤空闲时间
当线程数量超过corePoolSize后,其中的线程空闲时间达到keepAliveTime后,多余的线程就会被销毁直到剩下的线程数量为corePoolSize为⽌
4.timeUnit:keepAliveTime的时间单位
最⼤空闲时间的计量单位。
5.workQueue:任务队列
⼯作队列,存放被提交但尚未执⾏的任务。
5.1 ArrayBlockingQueue 数组组成的有界阻塞队列
此队列按照先进先出(FIFO)的原则对元素进⾏排序。默认情况下不保证访问者公平的访问对列,所谓公平是指阻塞堆列线程可按照阻塞的顺序访问队列。⾮公平性对先等待的线程是不公平的,当队列可⽤时,阻塞队列的线程都可以竞争访问队列的资格。
5.2 LinkedBlockingQueue 链表组成的有界阻塞队列参数为Integer.MAX_VALUE
此队列按照先进先出的原则对元素进⾏排序。
5.3 LinkedTransferQueue 链表组成的⽆界阻塞队列
相⽐于其他队列,LinkedTransferQueue多了tryTransfer和transfer⽅法
5.4 LinkedBlockingDeque 链表组成的双向阻塞队列
5.5 PriorityBlockingQueue ⽀持优先级排序的⽆界阻塞队列
此队列逻辑上是⽆界的,但是资源耗尽时试图执⾏add也将失败,导致OOM
5.6 DelayQueue 优先队列实现的延迟⽆界阻塞队列
只有在延迟期满之后才能从中提取元素。
5.7 SynchronousQueue 不存储元素的队列⼜称单元素队列
其中⼀个线程的插⼊操作必须等待另⼀个线程的对应移除操作,反之亦然。
线程池中最常⽤的是ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue
队列中常⽤的⽅法:
add() 向队列添加⼀个元素,如果队列已满,抛出IllegalStageException
remove() 移除队列头节点元素,如果对列为空,抛出NoSuchElementException
element() 检查队列,由元素就返回头节点,否则抛出NoSuchElementException
offset() 向队列中添加⼀个元素,成功返回true,失败返回false
poll() 删除队列中的头节点,成功返回元素,失败返回null
peek() 检查队列,由元素返回头节点,对列为空则返回null
put() 向队列中添加元素,如果队列满了就阻塞
take() 从队列中删除并返回头节点,如果列队中没有元素就阻塞
6.threadFactory:线程⼯⼚
表是线程池中⽣成⼯作线程的线程⼯⼚,⼀般使⽤默认即可(Executors.defaultThreadFactory())。它主要是为了给线程池起⼀个标识,也就是为线程池起⼀个具有意义的名称。
也可以⾃⼰实现ThreadFactory接⼝:
1).创建线程以后,等待提交过来的任务请求
2).当调⽤executor()或者submit()⽅法添加⼀个请求任务时,线程池会做如下判断:
如果正在运⾏的线程数量⼩于corePoolSize,那么马上安排线程执⾏这个任务。
如果正在运⾏的线程数量⼤于等于corePoolSize,那么就将任务放到任务队列中
如果任务队列没满就成功放⼊队列
如果任务队列满了并且正在运⾏的线程数⼩于maximumPoolSize,就创建⾮核⼼线程⽴刻执⾏这个任务(这⾥创建的线程不是⾸先去执⾏队列中的任务)。
如果队列满了且正在运⾏的线程数量⼤于等于maximumPoolSize,那么线程池就会启动饱和拒绝策略;
java线程池创建的四种3).当⼀个线程执⾏完当前任务后,它会从队列中取下⼀个任务来执⾏。
4).当⼀个线程⽆事可做,空闲时间超过keepAliveTime,线程池就会判断:
如果当前线程池中线程数量⼤于corePoolSize,那么这个线程就会被回收
直到线程池中线程数量收缩到corePoolSize。
2.实现线程池的⽅式:
1).通过Executors⼯具类创建:
带有时间调度的线程池 (每秒执⾏等)
ScheduledExecutorService scheduledExecutorService = wScheduledThreadPool(5);
指定线程数的线程池 适⽤于处理长期任务
ExecutorService fixedThreadPool = wFixedThreadPool(5);
⼀池⼀线程 适⽤于⼀个任务接⼀个任务的场景
ExecutorService singleThreadExecutor = wSingleThreadExecutor();
⼀池多线程,带缓存 适⽤于处理量较⼤的短期任务
ExecutorService cachedThreadPool = wCachedThreadPool();
使⽤⽬前机器上可⽤的处理器作为它的并⾏级别。 Java8之后的
ExecutorService workStealingPool = wWorkStealingPool();
上述的前四种线程池创建,最终构造⽅法都是⽤了ThreadPoolExecutor类的同⼀个构造器,只不过是所传参数的区别,构造器源码如下
package urrent;
public class ThreadPoolExecutor extends AbstractExecutorService {
//略...
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = SecurityManager() == null ?
null :
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = Nanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
}
但是,在在阿⾥巴巴Java开发⼿册中,不建议直接使⽤Executors去创建:
线程池不允许使⽤Executors去创建,⽽是通过ThreadPoolExecutors的⽅式,
这样的处理⽅式让写的同学更加明确线程池的运⾏规则,规避资源耗尽的风险
Executors返回的线程池对象的弊端如下:
(1).wFixedThreadPool()和wSIngleThreadExecutor()⽅法在调⽤构造器的时候传⼊的workQueue参数为new LinkedBlockingQueue<Runnable>(),此队列长度为Integer.MAX_VALUE,源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
这样做可能导致⼤量堆积请求到队列,造成OOM。
(2).wScheduledThreadPool()和wCachedThreadPool⽅法在调⽤构造器的时候,传⼊的参数maximumPoolSize为Integer.MAX_VALUE,源码如下:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论