线程池中为什么要使用阻塞队列?
来源:互联网 发布:sql联合主键查询 编辑:程序博客网 时间:2024/06/06 15:50
在线程池中活跃线程数达到corePoolSize时,线程池将会将后续的task提交到BlockingQueue中,为什么这样设计呢?
在一个task提交到线程池时,假设可以被线程池中的一个线程执行,则进行以下过程:
exeute ---》addWorker(Runnable command, boolean core)---》workers.add(w),启动线程执行任务(获取全局锁ReentrantLock mainLock)
具体源码如下:
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); //如果当前正在运行的线程数小于corePoolSize,则创建新的线程 //执行当前任务 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } //如果当前运行的线程数大于等于corePoolSize或者线程创建失败 //则把当前任务放入工作队列 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); //判断之前是否已经添加过线程执行该任务(因为可能之前) //创建的线程已经死亡了)或者线程池是否已经关闭。如果 //两个答案都是肯定的,那么选择拒绝执行任务 if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } //如果线程池任务无法加入到工作队列(说明工作队列满了) //创建一个线程执行任务。如果新创建后当前运行的线程数大于 //maximumPoolSize则拒绝执行任务 else if (!addWorker(command, false)) reject(command); }
private boolean addWorker(Runnable firstTask, boolean core){ //省略部分代码 boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { //这里就将提交的任务封装成为Worker了 w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { //使用加锁的方式原子添加工作线程 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //在获得锁期间再次检查线程池的运行状态:如果 //线程池已经关闭或者任务为空则抛出异常 int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) throw new IllegalThreadStateException(); //加入Worker数组 workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { //如果添加成功则启动线程执行任务 t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted; }
上述代码中:
w = new Worker(firstTask);final Thread t = w.thread;
Worker实现了Runnable接口,里面定义了一个final变量Thread thread
Worker的构造函数为:
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this);}run函数为:
public void run() { runWorker(this);}
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); try { beforeExecute(wt, task); Throwable thrown = null; task.run(); afterExecute(task, thrown); } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
看完上述代码后,我们可以得出:
线程池创建线程需要获取mainlock这个全局锁,影响并发效率,阻塞队列可以很好的缓冲。
另外一方面,如果新任务的到达速率超过了线程池的处理速率,那么新到来的请求将累加起来,这样的话将耗尽资源。
阅读全文
1 0
- 线程池中为什么要使用阻塞队列?
- 线程池阻塞队列
- 线程池和阻塞队列
- 线程池和阻塞队列
- 线程池和阻塞队列
- 线程池和阻塞队列的组合使用
- Java 使用线程经验之阻塞队列
- kernel/power/wakelock.c 中为什么要使用工作队列线程?
- 线程池+阻塞队列 模仿生产者消费者
- 线程池ThreadPoolExecutor与阻塞队列BlockingQueue
- 面试-阻塞队列及线程池
- 并发之阻塞队列&线程池
- Java线程池和阻塞队列
- java线程池和消息阻塞队列
- 线程通信---使用阻塞队列(BlockingQueue)控制线程通信
- 多线程 队列 线程阻塞
- Java中阻塞队列的使用
- 为什么要使用队列
- 我的第一篇
- 【算法】【Divide and conquer】Different Ways to Add Parentheses
- 1028. 人口普查(20)
- 正则表达式 反向引用
- Tensorflow truncated_normal API
- 线程池中为什么要使用阻塞队列?
- [性能调优]PeopleSoft Trace 分析工具
- HDOJ HDU 1060 Leftmost Digit
- cxf整合Spring框架进行服务端开发,并且通过cxf生成客户端代码进行调用
- JavaScript对象要点
- 数据结构之栈的使用
- static关键字修饰变量的加载和初始化过程(Java)
- 正则表达式 零宽断言(正向和负向)
- [HNOI]2003 消防局的建立