java阻塞队列和线程池工作队列
什么是阻塞队列,简单来讲,就是我们往队列里面添加东西时,如果满了就会执行一定的操作,比如阻塞那个加入元素的线程,而取出元素时,如果队列为空,也会执行一定的操作,比如阻塞那个取元素的线程
java中常见的几个阻塞队列
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
- LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
- DelayQueue:一个使用优先级队列实现的无界阻塞队列。
- SynchronousQueue:一个不存储元素的阻塞队列。
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
这些所谓的阻塞队列,常用于生产者消费者模型,一个队列为空,消费者就会阻塞,一个队列满了,生产者就会阻塞。
在线程池中就会用于线程池中的工作队列,用于存储任务
ArrayBlockingQueue队列
这是个以数组为基础
七大参数
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 = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
四大拒绝策略
当我们的工作队列满了,而线程的总个数也达到了线程的最大个数,这时候就会执行拒绝策略了,拒绝策略主要有:
- CallerRunsPolicy
- AbortPolicy
- DiscardPolicy
- DiscardOldestPolicy
CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//只要这个线程池没有关掉,那么就可以接受这个线程云心
if (!e.isShutdown()) {
//注意了,这里要分清楚连个所谓的“线程”,一个是本身线程池的线程,一个是传过来的Runable
r.run();
}
}
}
这里要区分run和start,我们需要注意这里有两种线程,一种是线程池的线程,二是由线程池调用者传过来的任务线程也就是Runnable对象,在执行这个拒绝策略的时候,是调用了Runnable的run方法,而不是start方法,所以java并没有特意为这个Runnable对象去独立一个线程出来,所以会等Runnable对象的run方法执行完,才能继续往下,而如果是start的话,调用完start就继续往下了,而不管start继续执行run有关了。所以这里变成了同步,而不是异步,没有真正开出一个线程,而仅仅是包装到调用者里面去了。
另外这个拒绝策略是没有对其这个线程,而是交给调用者的线程去执行了。
AbortPolicy
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
//这个拒绝策略简单,直接抛弃掉,并且抛出异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
//这个拒绝策略没啥,比上面还简单,就直接丢弃,啥也不做,也不通知
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
//这里有点无聊
//会丢弃线程池工作队列中最老的线程,然后将这个线程加入进去
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
常用线程池
线程池的异常处理