Java newCachedThreadPool如何缓存线程

Java newCachedThreadPool如何缓存线程,java,multithreading,executorservice,java.util.concurrent,Java,Multithreading,Executorservice,Java.util.concurrent,根据Executor类中方法publicstaticexecutorservice newCachedThreadPool()的注释: Threads that have not been used for sixty seconds are terminated and removed from the **cache**. 我想知道缓存在哪里,它是如何工作的?因为我在ThreadPoolExecutor或它的超类中没有看到任何可能的静态集合变量。缓存word只是一个抽象。在内部,它使用H

根据
Executor
类中方法
publicstaticexecutorservice newCachedThreadPool()
的注释:

Threads that have not been used for sixty seconds are terminated and 
removed from the **cache**.

我想知道缓存在哪里,它是如何工作的?因为我在
ThreadPoolExecutor
或它的超类中没有看到任何可能的静态
集合
变量。

缓存
word只是一个抽象。在内部,它使用
HashSet
来保存线程。根据守则:

/**
 * Set containing all worker threads in pool. Accessed only when
 * holding mainLock.
 */
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
*包含池中所有工作线程的集合。仅在以下情况下访问
*拿着主锁。
*/
private final HashSet workers=new HashSet();
如果您对Runnable感兴趣,请提交
执行


newCachedThreadPool
使用
SynchronousQueue
来处理它们。

如果查看的代码,您将看到:

 /**
 * Set containing all worker threads in pool. Accessed only when
 * holding mainLock.
 */
private final HashSet<Worker> workers = new HashSet<Worker>();

我将仔细阅读实际的实现代码,记住这些指针将有助于您更清楚地理解。

从技术上讲,Worker
是一个
可运行的
,包含对
线程的引用,而不是
线程本身

让我们更深入地研究这门课的机制

Executors.cachedThreadPool
使用
ThreadPoolExecutor

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
此时您已经提交了一个任务,并且创建了一个线程并运行它。

工人搬迁 如果您注意到有一个while循环,请在
运行
方法中。 这是一段非常有趣的代码

如果任务不为空,它将短路,不检查第二种情况

一旦任务使用
runTask
运行并且任务引用被设置为null,调用就会进入第二个检查条件,该条件将其带入
getTask
方法

这是决定工人是否应该被清洗的部分

workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
在这种情况下,将轮询工作队列一分钟,以检查队列中是否有任何新任务。 如果不是,它将返回null并检查worker是否可以退出

返回null意味着我们将突破while,最终进入

在这里,工作线程从HashSet中移除,引用的线程也消失了

缓存方面 回到我们在任务提交中讨论的SynchronousQueue

如果我提交了一个任务,其中
workerQueue.offer
workerQueue.poll
能够协同工作,即在这60秒之间有一个任务要处理,我可以重新使用线程

如果我在每次任务执行之间设置59秒对61秒的睡眠时间,就可以看到这一点

对于59秒,我可以看到线程得到重复使用。对于61s,我可以看到池中创建了一个新线程

注意:实际计时可能因机器而异,我的
run()
只是打印出
Thread.currentThread().getName()


如果我遗漏了什么或误解了代码,请在注释中告诉我。

为什么您希望它是静态的?它是
java.util.concurrent.ThreadPoolExecutor#workers
集合。为什么您认为is必须是静态的?不管其他代码如何,您上面提到的while循环和SynchronousQueue使线程池可以重用并且无限活跃,对吗?提交的任务实际上缓存在HashSet workers中,对吗?与其他代码无关。密钥是工作队列中的轮询部分。阅读工人移除部分,了解工人是如何移除的。同时进行59s vs 61s练习。如果提交并处理的第一个任务在60秒内或超过1分钟时没有提交更多任务,则创建的线程将是gc()。但是谁持有HashSet工作人员的引用?如果没有对worker的引用,它如何缓存线程?对worker的引用来自
ThreadPoolExecutor
实例,在executor关闭之前不会对其进行gc'ed。哦,这很有意义。谢谢:)
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
public void run() {
    try {
        Runnable task = firstTask;
        firstTask = null;
        while (task != null || (task = getTask()) != null) {
            runTask(task);
            task = null;
        }
    } finally {
        workerDone(this);
    }
}
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);