我试图通过重用可运行对象而不是为线程池中的每个任务创建一个新对象来提高 Dijkstra 算法的效率。每个任务需要 3 个参数(起始值、结束值和 CountDownLatch)。我尝试使用 getters/setters,除了线程类的 run() 方法之外,这在任何地方都有效。它不断重用一个变量,这搞砸了算法
这是线程类,run() 执行一个方法来查找图中下一个最近的节点。变量和 getter 是全局的:
//Thread class
class ClosestNodeTask implements Runnable {
@Override
public void run() {
getNodeShortestDistanced(getStart(), getEnd(), getCdlClosest());
}
}
下面的代码片段在 apply() 方法中执行。
创建对象(一次):
ClosestNodeTask closestNodeTask = new ClosestNodeTask();
此代码段给出了线程池要执行的任务:
for (int t = 0; t < numberOfThreads; t++) {
int start;
int end;
if (nodesModulo > 0 && numberOfThreads == (t + 1)) {
start = nodesPerThread * (t);
end = nodesPerThread * (t + 1) + nodesModulo;
setStart(start);
setEnd(end);
setCdlClosest(cdlClosest);
executor.execute(closestNodeTask);
} else {
start = nodesPerThread * t;
end = nodesPerThread * (t + 1);
setStart(start);
setEnd(end);
setCdlClosest(cdlClosest);
executor.execute(closestNodeTask);
}
}
“start”变量的输出有两个线程:0 和 12500。如果我在可运行对象的 run() 中执行 getstart(),它总是返回 12500,从而搞乱了算法。如果我在其他地方执行 getstart() ,我总是会得到正确的输出 0 和 12500。
我做错了什么?我不明白为什么 run() 方法不断重用相同的变量。
最佳答案
当您创建单个对象并在多个线程中使用它时,您实际上是在与所有这些线程共享一个公共(public)状态。也就是说,当您可以 setStart() 等时,您正在为所有正在运行的线程以及您正在创建的新线程设置启动。
每个线程都需要单独的对象。这要么是您正在运行的类的单独实例的形式,要么是线程局部变量的形式,效率较低。
关于Java ThreadPool 重用可运行对象,而不是为每个任务创建新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59214860/