今天跟别人讨论了线程池的核心线程会不会销毁的问题
先上代码

public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor pool = new ThreadPoolExecutor(4,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(20));//pool.allowCoreThreadTimeOut(true);int a = 10;for (int i = 1; i <= a; i++) {int j = i;pool.submit(new Runnable() {@Overridepublic void run() {if(j == 10){throw new RuntimeException();}//获取线程名称Thread thread = Thread.currentThread();String name = thread.getName();//输出int activeCount = pool.getActiveCount();System.out.println("任务:"+j+"-----,线程名称:"+name+"-----活跃线程数:"+activeCount+"-----线程数"+pool.getPoolSize());}});}Thread.sleep(6000);System.out.println("线程数"+pool.getPoolSize()+"-----,活跃线程数"+pool.getActiveCount());
}

结果:活跃线程数为0,池内线程数量为核心线程数(这里要注意getPoolSize和getActiveCount不要混为一谈!!!线程不活跃了但是还是在池子里!!!只是空闲了,另外看评论区可能有一些同学会误解,这里是在线程池完全空闲时,用getPoolSize的数量与corePoolSize数量一致来说明线程池的确创建了4个核心线程池,而不是说getPoolSize就是核心线程数)如果对线程池原理不够理解,点这里

大家可能看到我注释了一行代码,那么就看看不注释掉的运行结果

public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor pool = new ThreadPoolExecutor(4,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(20));pool.allowCoreThreadTimeOut(true);int a = 10;for (int i = 1; i <= a; i++) {int j = i;pool.submit(new Runnable() {@Overridepublic void run() {if(j == 10){throw new RuntimeException();}//获取线程名称Thread thread = Thread.currentThread();String name = thread.getName();//输出int activeCount = pool.getActiveCount();System.out.println("任务:"+j+"-----,线程名称:"+name+"-----活跃线程数:"+activeCount+"-----线程数"+pool.getPoolSize());}});}Thread.sleep(6000);//一定要大于KeepAliveTime的值System.out.println("线程数"+pool.getPoolSize()+"-----,活跃线程数"+pool.getActiveCount());
}

结果:核心线程被销毁了,线程数为0:


corePoolSize:返回核心线程数,类似于配置,不会随着核心线程被销毁而改变,所以我们用getPoolSize来进行验证

/*** Core pool size is the minimum number of workers to keep alive* (and not allow to time out etc) unless allowCoreThreadTimeOut* is set, in which case the minimum is zero.*/private volatile int corePoolSize;

allowCoreThreadTimeOut:设置控制核心线程是否可以超时并终止的策略,如果在保活时间内没有任务到达,则在新任务到达时根据需要替换。当为 false 时,核心线程永远不会由于缺少传入任务而终止。如果为真,则适用于非核心线程的相同保活策略也适用于核心线程。为避免持续的线程替换,设置 true 时保持活动时间必须大于零。通常应该在主动使用池之前调用此方法。

/*** If false (default), core threads stay alive even when idle.* If true, core threads use keepAliveTime to time out waiting* for work.*/private volatile boolean allowCoreThreadTimeOut;

getPoolSize:返回线程池当前线程数

/*** Returns the current number of threads in the pool.** @return the number of threads*/public int getPoolSize() {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {// Remove rare and surprising possibility of// isTerminated() && getPoolSize() > 0return runStateAtLeast(ctl.get(), TIDYING) ? 0: workers.size();} finally {mainLock.unlock();}}

源码:直接看runWorker的processWorkerExit

final void runWorker(Worker w) {Thread wt = Thread.currentThread();Runnable task = w.firstTask;w.firstTask = null;w.unlock(); // allow interruptsboolean completedAbruptly = true;try {while (task != null || (task = getTask()) != null) {w.lock();// If pool is stopping, ensure thread is interrupted;// if not, ensure thread is not interrupted.  This// requires a recheck in second case to deal with// shutdownNow race while clearing interruptif ((runStateAtLeast(ctl.get(), STOP) ||(Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted())wt.interrupt();try {beforeExecute(wt, task);Throwable thrown = null;try {task.run();} catch (RuntimeException x) {thrown = x; throw x;} catch (Error x) {thrown = x; throw x;} catch (Throwable x) {thrown = x; throw new Error(x);} finally {afterExecute(task, thrown);}} finally {task = null;w.completedTasks++;w.unlock();}}completedAbruptly = false;} finally {//无论如何都会执行到这个方法processWorkerExit(w, completedAbruptly);}
}

看来重点在processWorkerExit方法

private void processWorkerExit(Worker w, boolean completedAbruptly) {if (completedAbruptly) // If abrupt, then workerCount wasn't adjusteddecrementWorkerCount();final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {completedTaskCount += w.completedTasks;workers.remove(w);} finally {mainLock.unlock();}tryTerminate();int c = ctl.get();if (runStateLessThan(c, STOP)) {if (!completedAbruptly) {//allowCoreThreadTimeOut 默认false 即 min默认为corePoolSizeint min = allowCoreThreadTimeOut ? 0 : corePoolSize;//如果min为0但是工作队列不为空,则至少要创建一个新的workerif (min == 0 && ! workQueue.isEmpty())min = 1;if (workerCountOf(c) >= min)return; // replacement not needed}addWorker(null, false);}
}

结论:当allowCoreThreadTimeOut手动设置为true或者执行的run方法抛出异常,核心线程都会被销毁,但是后者还是会创建新的线程称呼来,前者则销毁什么都不做,关键在于allowCoreThreadTimeOut为true则下面代码直接返回,不在执行addWorker方法

if (workerCountOf(c) >= min)return; // replacement not needed

线程池的核心线程会销毁吗?相关推荐

  1. 【Java面试小短文】当任务数超过线程池的核心线程数,如何让它不进入阻塞队列直接启用最大数量的线程去执行任务?

    欢迎关注Java面试系列,不定期更新面试小短文.欢迎一键三连! 当任务数超过线程池的核心线程数,如何让它不进入阻塞队列直接启用最大数量的线程去执行任务? 当我们提交一个任务到线程池,它的工作原理如下: ...

  2. Java线程池的核心线程数和最大线程数

    Java的线程池就像是一个花瓶容器. 而把任务提交给线程池就像是把小球塞进花瓶. 整个过程就像下面这个有趣的动画: 下面我们先来了解一下Java线程池的参数. 希望看完这篇文章后, 再提起线程池的时候 ...

  3. 线程池的核心线程数、队列和最大线程数

    通常情况下线程池只创建核心线程,核心线程满后进来的线程在队列中排队等候,队列满后线程池可以创建非核心线程运行新线程,直到达到最大线程数后再加入新线程抛出异常.

  4. 线程池:治理线程的法宝

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Oo鲁毅oO juejin.im/post/5e1b1fcc ...

  5. 【Android 异步操作】线程池 ( 线程池作用 | 线程池种类 | 线程池工作机制 | 线程池任务调度源码解析 )

    文章目录 一.线程池作用 二.线程池种类 三.线程池工作机制 四.线程池任务调度源码解析 一.线程池作用 线程池作用 : ① 避免创建线程 : 避免每次使用线程时 , 都需要 创建线程对象 ; ② 统 ...

  6. 自定义线程池内置线程池的使用 ThreadPoolExecutor和Executorservice 示例与注意事项

    文章目录 线程池介绍 自己设计一个线程池 1.设计ThreadPool类: 2.设计工作队列 3.实现自己设计的线程池 用java的ThreadPoolExecutor自定义线程池 自定义线程池-参数 ...

  7. 【Java线程】“打工人”初识线程池及自定义线程池实战

    目录 理论 原理 线程池创建 工作流程图 拒绝策略 参数设置 四种线程池 实战 理论 聊一下为什么要使用线程池? 程序的运行本质,就是通过使用系统资源(CPU.内存.网络.磁盘等等)来完成信息的处理, ...

  8. JAVA线程池_并发队列工作笔记0002---认识线程池_在线程池中使用队列

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 上面是线程的执行周期 这个线程的生命周期,可以看到时间都浪费在了创建和销毁的这里了. 实际上执行业 ...

  9. java线程池功能_Java线程池总结

    一.线程池 线程池适合处理的任务:执行时间短.工作内容较为单一. 合理使用线程池带来的好处: 1)降低资源消耗:重复利用已创建的线程降低线程创建和销毁造成的开销 2)提高响应速度:当任务到达时,任务可 ...

最新文章

  1. 使用Python PIL库实现简单验证码的去噪处理
  2. java字典序列化_Java对象序列化,Serialize Java Data Object,音标,读音,翻译,英文例句,英语词典...
  3. C++ 二分查找函数 lower_bound upper_bound
  4. Angular6自定义指令实现多图片上传预览
  5. 在下载jar包时,要有三个包,分别为使用的把class、查看文档的api、查看源代码的资源包...
  6. Symfony2模版引擎使用说明手册
  7. 培训学习笔记 - 人们不买钻头,他们买孔洞
  8. 登录表单 参考新浪微博
  9. sqlserver2008导出mysql_SQLserver 2008将数据导出到Sql脚本文件的方法
  10. 使用Python进行地理编码和反向地理编码
  11. jQuery使用ajax跨域请求获取数据
  12. BZOJ.2555.SubString(后缀自动机 LCT)
  13. http://blog.seirsoft.com
  14. mfc 子窗体任何消息都不触发_你不知道的 WebSocket
  15. PC QQ客户端播放语音或者短视频消息无声音解决
  16. pnpm monorepo的技术选型临界点(Critical adoption)
  17. 1N4148的导通电压
  18. Windows Server 中 DNS 服务器的新增功能
  19. 系分 - 操作系统 - 嵌入式
  20. 攻防兼备:中国蚁剑使用指南及特征流量

热门文章

  1. 2D制作动画软件:Cartoon Animato 支持win/mac 中文激活版
  2. [转载]倒库移库技巧图解
  3. 网赚项目分享:八条可以在线上做的副业兼职
  4. 黎想首谈14大权威新媒体推广平台,教你一招搭建信息流矩阵!
  5. imToken—钱包如何导出助记词?
  6. Leetcode 中等:89.格雷编码
  7. 英语口语196之每日十句口语
  8. 取消打印机选择框实现
  9. python tkinter画福字
  10. task02 EDA