根据public static ExecutorService newCachedThreadPool()
类中的方法Executor
的评论:
Threads that have not been used for sixty seconds are terminated and
removed from the **cache**.
我想知道缓存在哪里以及它是如何运作的?因为我在Collection
或它的超类中没有看到任何可能的静态ThreadPoolExecutor
变量。
答案 0 :(得分:3)
技术上Worker
是一个Runnable
,其中包含对Thread
的引用,而不是Thread
的引用。
让我们深入研究这门课程的机制。
Executors.cachedThreadPool
使用ThreadPoolExecutor
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
其中60s对应keepAliveTime
时间。
从提交的RunnableFuture
或Callable
创建Runnable
这传递给execute()
方法。
execute
方法尝试将任务插入workQueue
,在我们的例子中是SynchronousQueue
。由于SynchronousQueue
的语义,这将失败并返回false
(坚持这个想法,当我们讨论缓存方面时,我们将重新审视这个问题)
此调用将继续addIfUnderMaximumPoolSize
execute
内的java.util.concurrent.ThreadPoolExecutor.Worker
方法,该方法将创建Worker
可运行并创建一个主题并将创建的workers
添加到thread.start()
hashSet。 (其他人在答案中提到过)
然后调用public void run() {
try {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
runTask(task);
task = null;
}
} finally {
workerDone(this);
}
}
。
工人的跑步方法非常重要,应该注意。
run
此时您已提交任务并创建并运行该线程。
在runTask
方法中,如果您注意到有一个while循环。
这是一段令人难以置信的有趣代码。
如果任务不为空,它将短路而不检查第二个条件。
使用getTask
运行任务并且任务引用设置为null后,调用将进入第二个检查条件,该条件将其转换为workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
方法。
这是决定工人是否应该被清除的部分。
finally
在这种情况下,轮询workQueue一分钟,以检查队列中是否有新任务。 如果不是,它将返回null并检查worker是否可以退出。
返回null表示我们将暂时退出workerQueue.offer
块。
这里将工作者从HashSet中删除,引用的Thread也消失了。
回到我们在任务提交中讨论的SynchronousQueue。
如果我提交的任务workerQueue.poll
和run()
能够协同工作,即在60年代之间有一个任务需要处理,我可以重新使用该线程。
如果我在每次任务执行期间将59s与61s的睡眠放在一起,可以看到这一点。
59s我可以看到线程被重用了。对于61s我可以看到在池中创建了一个新线程。
N.B。实际时间可能因机器而异,我的Thread.currentThread().getName()
只是打印出{{1}}
如果我遗漏了某些内容或误解了代码,请在评论中告诉我。
答案 1 :(得分:1)
Cache
这个词只是一个抽象。在内部,它使用HashSet
来保存线程。根据代码:
/**
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
如果你对submit
或execute
的runnable感兴趣的话。
newCachedThreadPool
使用SynchronousQueue<Runnable>
来处理它们。
答案 2 :(得分:0)
如果您查看ThreadPoolExecutor的代码,您会看到:
/**
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
和此:
/**
* The queue used for holding tasks and handing off to worker
* threads. We do not require that workQueue.poll() returning
* null necessarily means that workQueue.isEmpty(), so rely
* solely on isEmpty to see if the queue is empty (which we must
* do for example when deciding whether to transition from
* SHUTDOWN to TIDYING). This accommodates special-purpose
* queues such as DelayQueues for which poll() is allowed to
* return null even if it may later return non-null when delays
* expire.
*/
private final BlockingQueue<Runnable> workQueue;
而且:
try {
Runnable r = timed ?
// here keepAliveTime is passed as sixty seconds from
// Executors#newCachedThreadPool()
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
我真诚地介绍了实际的实现代码,记住这些指针将有助于您更清楚地理解。