【问题标题】:Java ThreadPool reuse runnable object instead of creating new object for each taskJava ThreadPool 重用可运行对象,而不是为每个任务创建新对象
【发布时间】:2020-03-31 13:09:54
【问题描述】:

我试图通过重用可运行对象而不是为线程池中的每个任务创建一个新对象来提高我的 Dijkstra 算法的效率。每个任务需要 3 个参数(开始值、结束值和 CountDownLatch)。我尝试使用 getter/setter,除了线程类的 run() 方法外,它在任何地方都有效。它不断重用一个变量,这搞砸了算法

这是线程类,run() 执行一个方法来查找图中下一个最近的节点。变量和 getter 是全局的:

//Thread class
        class ClosestNodeTask implements Runnable {

            @Override
            public void run() {
                getNodeShortestDistanced(getStart(), getEnd(), getCdlClosest());
            }
        }

下面的代码 sn-ps 在 apply() 方法中执行。

对象的创建(一次):

ClosestNodeTask closestNodeTask = new ClosestNodeTask();

这个sn-p给出线程池执行的任务:

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() 方法不断重用同一个变量。

【问题讨论】:

  • 你已经在开头说过你做错了什么:“我正在尝试通过重用可运行对象来提高我的 Dijkstra 算法的效率”。当您重用对象时,算法不会变得更有效。当“每个任务需要 3 个参数”时,您必须为每个任务创建一个包含 3 个参数的对象。

标签: java concurrency threadpool runnable dijkstra


【解决方案1】:

当您创建一个对象并在多个线程中使用它时,您实际上是在与所有这些线程共享一个公共状态。也就是说,当您可以 setStart() 等时,您正在为所有正在运行的线程以及正在创建的新线程设置启动。

每个线程都需要单独的对象。这要么是你正在运行的类的单独实例的形式,要么是作为线程局部变量的形式,效率较低。

【讨论】:

  • 换句话说:您无法按照您描述的方式优化您的代码,因为这样做会引入您发现的相同错误。
猜你喜欢
  • 2017-04-12
  • 2017-04-23
  • 2013-07-06
  • 2013-08-07
  • 2017-02-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
相关资源
最近更新 更多