ThreadPool的优点,比如资源的控制以及不用频繁的创建线程等就不用多说了。主要来讨论一下ThreadPoolExecutor的几个关键参数以及对task的添加以及线程的管理。它有这么个重要的参数corePoolSize、maximumPoolSize、keepAliveTime和taskqueue。
corePoolSize 线程池维持处于Keep-alive状态的线程数量。如果设置了allowCoreThreadTimeOut为true,该值可能为0。
maximumPoolSize 线程池中可维持线程的最大值。
keepAliveTime 当线程池中线程数量大于 corePoolSize 时,如果某些线程的空闲时间超过该值就会终止,直到线程数小于等于corePoolSize。
1. 添加一个task的过程
当要添加一个新的task,如果当前线程数小于 corePoolSize,直接添加一个线程,即使当前有空闲的线程。否则添加队列中。如果队列满了呢?则会判断当前线程数是否小于maximumPoolSize,如是则添加一个新的线程用来执行该task。如果超出最大线程数,那就只能reject了。
int c = ctl.get(); // 当前线程数小于corePoolSize if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } //添加到队列中 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则reject else if (!addWorker(command, false)) reject(command);
使用addWorker(),来创建新的线程并传入的task作为第一个task执行。由此来看只有队列满时才会创建大于corePoolSize的线程。
2. KeepAliveTime是如何实现的呢?
keepAliveTime的职责时,当线程池的队列满了,创建了多于corePoolSize的线程,这时处于节省资源的目的,会杀死多于corePoolSize空闲时间大于keepAliveTime的线程。它是如何做到呢?我们知道Woker时从taskQueue不断地轮询获取task并执行。如果获取不到task取到null时则退出循环结束线程。大概源码是这样的。
try { //当取到task为null,跳出循环结束线程 while (task != null || (task = getTask()) != null) { w.lock(); clearInterruptsForTaskRun(); //此处省略,主要是执行task.run }
关键是看看getTask()如何返回null,该方法的comments列出几种返回null并减少当前线程数的情景。我们在这里只关心keeAliveTime的实现。
boolean timedOut = false; // Did the last poll() time out? 该变量标识从taskqueue中取任务是否超时,如果超时则返回null retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); // Check if queue empty only if necessary. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null; } boolean timed; // Are workers subject to culling? for (;;) { int wc = workerCountOf(c); timed = allowCoreThreadTimeOut || wc > corePoolSize;//线程数大于corePoolSize满足了杀死空闲线程的条件 //第一次执行到这里,由于timeOut为false,跳出内循环执行从queue取任务 if (wc <= maximumPoolSize && ! (timedOut && timed)) break; //第二次执行的时候由于timedOut为true,不会跳出内循环。执行下面的代码 //将当前线程数减1并返回null致使该线程终止 if (compareAndDecrementWorkerCount(c)) return null; c = ctl.get(); // Re-read ctl if (runStateOf(c) != rs) continue retry; // else CAS failed due to workerCount change; retry inner loop } try { //timed为true,这段code是实现空闲时间超过keepalivetime就被终止的精华所在。 // 在给定的keepalivetime时间内从阻塞队列中取任务。如timeout则返回null Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true;//如从queue中取任务超时则为true } catch (InterruptedException retry) { timedOut = false; } }
相关推荐
Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程Java后端开发,JUC并发编程...
而了解 Java 并发编程以及其中的 JUC(java.util.concurrent)线程池,对于构建高性能、高可伸缩性的应用程序具有重要意义。 多核处理器的出现使得并发执行成为一种重要的优化手段。了解并发编程和线程池的工作原理...
java高级技术JUC高并发编程教程2021(1.5G) 〖课程介绍〗: java高级技术JUC高并发编程教程2021(1.5G) 〖课程目录〗: 01-JUC高并发编程-课程介绍.mp4 02-JUC高并发编程-JUC概述和进程线程概念(1).mp4 03-JUC...
JUC并发编程知识点梳理思维导图
B站楠哥JUC Java并发编程
juc并发编程脑图以及相关示例代码
Java 并发编程中的 JUC(java.util.concurrent)库以及其核心组件 AQS(AbstractQueuedSynchronizer)在构建高性能、可伸缩性的多线程应用方面具有重要的地位。 AQS 是 JUC 中的核心组件,它提供了一个框架,让...
【尚硅谷】大厂必备技术之JUC并发编程视频 配套资料,自己根据视频整理 pdf 课件,和代码 视频地址:...
阿里专家级并发编程架构师级课程,完成课程的学习可以帮助同学们解决非常多的JAVA并发编程疑难杂症,极大的提高JAVA并发编程的效率。课程内容包括了JAVA手写线程池,UC线程池API详解,线程安全根因详解,锁与原子类...
java并发编程学习笔记,很详细的资料
网盘文件永久链接
1、根据尚硅谷JUC并发编程(对标阿里P6-P7)视频自己整理的pdf文档 2、包含源码 视频地址:https://www.bilibili.com/video/BV1ar4y1x727/?p=1&vd_source=c634d163b940964d44747b4c3976117b 参考资料:...
JUC 笔记 基于JDK 17
JAVA并发编程体系梳理脑图
【小家java】JUC并发编程之:虚假唤醒以及推荐的解决方案.docx
Java 并发编程在现代软件开发中占据重要地位,尤其是在多核处理器的时代。JUC(java.util.concurrent)库是 Java 标准库的一部分,提供了丰富的多线程并发工具,旨在帮助开发者编写高性能、高可伸缩性的并发程序。...
这份资源为您提供了关于 Java 并发编程的全面讲解,着重介绍了 JUC(java.util.concurrent)库中的核心概念、工具和最佳实践。通过深入学习,您将能够更好地理解并发编程的挑战,掌握构建高性能、高可伸缩性的并发...
龙果学院java并发编程完整视频
cehi
Java高并发第三阶段(JUC).png 高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解.mkv 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍.mkv 高并发编程第三阶段03讲 利用CAS构造一...