Java线程池(1)
来源:互联网 发布:淘宝运营工资6000高吗 编辑:程序博客网 时间:2024/05/23 02:06
昨天正好面试的时候,问了面试者线程池的问题,问题时这样的:”ThreadPoolExecutor中,假如corePoolSize=5, maximumPoolSize=10, workQueue的长度也是5,此时我向这个线程池中提交6个Runnable,线程池此时如何处理这第六个Runnable?”。
这道题目很多面试者容易犯错,因为直观上,我们感觉线程池应该这样处理:
(1) 当线程池中的线程数目小于maximumPoolSize时,新来一个任务的话,应该新创建一个线程来处理;
(2) 当线程池中存活的线程的数目达到了maximumPoolSize之后,新来的任务应该会被防到队列中,等在线程忙完之后再来处理。
实际情况是这样吗?先做一个实验:
public class ThreadPoolTest { public static void main(String[] args) throws Exception{ ExecutorService executorService = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5)); List<Future> list = new ArrayList<Future>(); //创建5个长任务,每个长任务会运行1分钟左右的时候 int i = 5; while (i-- > 0) { list.add(executorService.submit(new LongRunnable())); } //提交一个短任务,段任务会打印它的运行时间 list.add(executorService.submit(new ShortRunnable())); //打印当前提交时间 System.out.println("submit time:" + new Date()); //等待所有的任务执行完 for(Future future : list) { future.get(); } executorService.shutdown(); } private static class ShortRunnable implements Runnable { @Override public void run() { System.out.println("run time: " + new Date()); } } private static class LongRunnable implements Runnable { @Override public void run() { int i = 60; while (i-- > 0) { try { Thread.sleep(1000L); }catch (Exception e) { e.printStackTrace(); } } } }
结果:
submit time:Tue Feb 23 15:05:28 CST 2016run time: Tue Feb 23 15:06:28 CST 2016
从结果中可以看出,第六个提交的任务的运行时间比他的提交时间大概晚了1分钟左右,也就是说,当我们提交第六个任务的时候,线程池并没有创建一个新的线程来运行它,而是等最开始创建的5个线程中有线程空闲了才来运行第六个任务。这时候我们提交的这个任务线程池把它放在哪的呢?应该是放在队列中的。
下面我们修改测试代码, 把list.add(executorService.submit(new ShortRunnable()));
修改成
i = 6; while (i-- > 0) { list.add(executorService.submit(new ShortRunnable())); }
再运行下看看:
run time: Tue Feb 23 15:20:06 CST 2016
submit time:Tue Feb 23 15:20:06 CST 2016
run time: Tue Feb 23 15:20:06 CST 2016
run time: Tue Feb 23 15:20:06 CST 2016
run time: Tue Feb 23 15:20:06 CST 2016
run time: Tue Feb 23 15:20:06 CST 2016
run time: Tue Feb 23 15:20:06 CST 2016
此时我们发现, 提交的6个任务全部瞬间运行完了。这也说明了线程池的运行过程是这样的:
(1) 当提交一个任务交给线程池,而此时线程池中并没有空闲的线程来处理时, 线程池会把任务放在队列中缓存起来;
(2) 如果缓存队列满了,新提交一个任务时,此时线程池会判断池中的线程数目是否大于或等于maximumPoolSize, 如果没有大于或等于,则新创建一个线程来处理改任务。如果线程池中的线程数目已经大于或等于maximumPoolSize, 则拒绝服务。
我们看ThreadPoolExecutor的源代码:
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) { if (runState == RUNNING && workQueue.offer(command)) { if (runState != RUNNING || poolSize == 0) ensureQueuedTaskHandled(command); } else if (!addIfUnderMaximumPoolSize(command)) reject(command); // is shutdown or saturated } } private boolean addIfUnderCorePoolSize(Runnable firstTask) { Thread t = null; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { if (poolSize < corePoolSize && runState == RUNNING) t = addThread(firstTask); } finally { mainLock.unlock(); } if (t == null) return false; t.start(); return true; }
从代码中可以看出,
(1) 当线程池中添加任务时,线程池首先会检查当前存活的线程是否已经达到了corePoolSize;
(2) 如果未达到,则创建一个新的线程来处理该任务;
(3) 如果存活线程数目已达到corePoolSize,或者创建新的执行线程失败,则执行runState == RUNNING && workQueue.offer(command)
把任务添加到队列中。
(4) 我们知道阻塞队列的offer方法是不阻塞的, 也就是当队列满了之后,workQueue.offer(command)会返回false,此时, 则添加线程来执行任务addIfUnderMaximumPoolSize(command)
;
(5) 如果addIfUnderMaximumPoolSize(command)
返回false, 则说明线程池中存活的线程数目已经达到了最大的线程数目, 则拒绝执行。
- Java线程池-1
- Java线程池(1)
- java线程池-1
- Java线程:线程池
- java--线程--线程池
- Java技术1-线程池
- Java线程池(1)--cachedTheadPool
- Java线程池学习(1)
- Java 线程池学习 Reference: 《创建Java线程池》[1],《Java线程:新特征-线程池》[2], 《Java线程池学习》[3],《线程池ThreadPoolExecutor使用简介
- Java线程模型、线程状态 - 线程(1)
- Java线程(六):线程池
- Java线程(五):线程池
- Java线程(五):线程池
- Java线程_07_线程池
- Java线程(五):线程池
- Java线程(六):线程池
- Java线程(五):线程池
- Java线程(六):线程池
- 第八章 多态
- TortoiseSVN客户端重新设置用户名和密码
- codeforces587B Duff in Beach
- 韩顺平 javascript教学视频_学习笔记25_bom介绍_dom对象层次图_dom对象(window对象1)
- wpf设计器显示图片,运行却不显示图片
- Java线程池(1)
- AFMWorking 网络监听
- HDU 1257最少拦截系统(贪心)
- swift-函数02-函数返回值
- Python练习-- condition
- fsl audio 架构介绍
- 配置管理和IT部门间的区别和联系
- Android IPC机制多进程模式
- Android 播放短音乐