- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想就 Zeller 一年多前发布的同一个问题询问更多细节...
javadoc 说 Executors.newCachedThreadPool
返回的服务重用了线程。这怎么可能?
我知道队列结构是如何在内部设置的,但我没有看到它如何重用队列中的线程。
我见过的所有示例都是让开发人员创建他们的线程实例并通过“执行”方法将其传递。
例如……
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread(i); //will create 10 instances
executor.execute(worker);
}
我知道线程池可以轻松管理每个线程的生命周期,但同样,我看不到任何方法,也看不到访问或重启池中任何线程的能力。
在上面的示例中,我希望每个线程都将由线程池启动、运行、终止和处理,但绝不会重用。
消息传递系统就是您需要它的示例。假设您有一个 onMessage 处理程序,并且您希望重用池中的线程之一来处理它,所以我期望像...这样的方法
worker = executor.getIdleThread;
worker.setData(message);
executor.resubmit(worker);
或者让 ExecutorService 充当工厂类并让它返回您的线程的一个实例,它在内部决定创建一个新线程或重用旧线程。
ExecutorService executor = Executors.newCachedThreadPool(WorkerThread);
Runnable worker = executor.getThread;
worker.setData(message);
所以我错过了一些东西。这可能很简单,但我花了一个下午阅读教程和示例,但仍然没有弄明白。有人可以阐明这个主题吗?
最佳答案
我也很好奇这怎么可能,因为Threads无法重启,所以我分析了ThreadPoolExecutor
的代码,它是所有ThreadPool ExecutorService
的实现通过静态构造函数。
首先,如其他答案所述,您不使用线程,而是使用线程池中的可运行对象,因为那样会破坏目的。所以这里详细解释了一个 ExecutorService 是如何重用线程的:
您通常通过 submit()
添加一个 Runnable,它在内部调用 execute()
方法。基本上这会将 runnable 添加到队列中,如果没有工作的 ATM,则添加一个 Worker
public void execute(Runnable command) {
...
int c = ctl.get();
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);
}
else if (!addWorker(command, false))
reje
ct(command);
}
执行器维护了一堆Worker(ThreadPoolExecutor
的内部类)。它具有您提交的可运行对象和一个线程,该线程将通过您可能设置的 ThreadFactory 创建,或者只是一个默认线程; Worker本身也是一个Runnable,用于从工厂创建Thread
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
...
Worker(Runnable firstTask) {
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
...
}
添加 Worker 时它会启动
private boolean addWorker(Runnable firstTask, boolean core) {
...
Worker w = new Worker(firstTask);
Thread t = w.thread;
...
t.start();
...
return true;
}
runWorker()
方法在循环中运行并通过 getTask()
获取您提交的在 workingQueue
中排队的可运行对象,并且将在 getTask 处等待,直到发生超时。
final void runWorker(Worker w) {
Runnable task = w.firstTask;
w.firstTask = null;
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
clearInterruptsForTaskRun();
try {
beforeExecute(w.thread, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
...
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
这里是 getTask() 方法
private Runnable getTask() {
...
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
..
} catch (InterruptedException retry) {
...
}
}
}
tl;dr 所以基本上,Threadpool 维护工作线程,这些工作线程在循环中运行并执行由阻塞队列提供的可运行对象。 worker 将根据需求创建和销毁(没有更多任务,worker 将结束;如果没有空闲 worker 并且 < maxPoolSize 则创建新的 worker)。此外,我不会将其称为“重用”,因为线程将用作循环程序来执行所有可运行对象。
关于java - newCachedThreadPool 是如何复用线程的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23641113/
本文书接上回《反DDD模式之关系型数据库》,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新; DDD框架源码(.NET、Java双平台); 加群畅聊,建模分析、技术实
我里面有 VC 和一个 collectionView。所有管理 Collection View 的代码我都放在那个 VC 的扩展中。但现在我需要在另一个不同的 VC 中使用这个 Collection
我很难重新使用子机图。 我需要重新使用我已链接到一个状态的状态机作为子机,在另一个状态中作为子机。但是当我给出对它的引用时,我得到一个空指针异常。 引用图片 我已经添加了对 GeneralTopup
我想尝试 lambda 的一些功能,并想编写一个 ArrayList 过滤器,并使用 IntStream 的方法来计算 ArrayList 中数字的平均值和最大值 我的第一个想法是过滤 ArrayLi
我正在开发一个 NodeJS 应用程序并使用 Mocha 进行单元测试。 假设我有两个非常相似的测试服。事实上,这些是针对两个类的测试实现相同的接口(interface)。 例如: suit_a.js
我正在使用 Glade 编写带有对话框的 python GUI。 如果我不使用 Glade,我会使用一个类来创建一个对话窗口 (dialag),运行它 (dialog.run),执行它所做的任何事情,
我在使用自定义单元格创建 UICollectionView 以显示项目时遇到问题。但是在 UICollectionView 刷新后,可重用的单元格填充了错误的索引 刷新前的 UICollectionV
我从 Sencha 学习 ExtJS 并有下一个简单的任务: 我的页面上有 2 个 div 在第一个 div 中我渲染 Ext.Button 在按钮上单击我想将其移动到另一个 div 仅此而已 我写了
我想在不同的 Node 模块中重用 RabbitMQ channel 。由于 channel 是异步创建的,我不确定将此 channel 对象“注入(inject)”到其他模块的最佳方法是什么。 如果
所以我的问题是我收到一个 SIGABRT 错误,其定义如下: *** Terminating app due to uncaught exception 'NSInvalidArgumentExcep
我正在编写一个 PHP 脚本来将主题从旧论坛站点迁移到新站点。 旧论坛站点使用数据库“old_forums” 新论坛站点使用数据库“new_forums” MySQL 用户“forums”拥有两个数据
我有一个使用 jcodec 生成的 MP4 文件。 然后我就有了一个使用 Android 的 MediaCodec 生成的 AAC 文件。 我想将它们混合到一个文件中,并且由于我不想将我的 Andro
我正在使用 ffmpeg 开发一个 c++ 项目。我必须生成一个带有 h264 编码的 mp4 文件。 我的问题是文件生成但是当用 VLC 读取文件时我没有图像,并用 ffprobe 分析它给我(下面
我将尝试重新提出这个问题。 我想要做的是创建一个新的 mp4 文件,其中将包括一个视频文件、两个音频文件和一个字幕文件。我想创建一个可以在我的 iOS 设备和计算机上播放的 mp4 文件。 文件如下:
虽然我的问题可能看起来很抽象,但我希望不是。假设我开发了一个应用程序,一个 ASP.NET MVC 站点,然后我的任务是为这个应用程序构建一个 Winforms 客户端,我可以从现有应用程序中重用多少
我是一名优秀的程序员,十分优秀!