使用 join() 的 Java 多线程程序在计算相邻数字之和时给出了错误的结果

标签 java multithreading concurrency java-threads java-memory-model

我编写了这个简单的多线程程序来将 1 到 100,000 之间的数字相加。当我运行这个时,我得到了不同的值作为最终结果(值小于预期的 5000050000 )。当我只使用一个线程执行程序时,它给出了正确的结果。程序也适用于较小的值,例如 100。可能出了什么问题?提前致谢。

class Calculation {

  private long total=0;
  public void calcSum(long start, long end) {
      long i = start;
      for( ;i<=end; i++) {
          total += i;
      }
  }
  public long getTotal() {
     return total;
  }
}

class CalculatorThread extends Thread{
   private long start;
   private long end;
   private Calculation calc;
   public CalculatorThread(long start, long end, Calculation calc) {
       this.start = start;
       this.end = end;
       this.calc = calc;
   }
   @Override
   public void run() {
       calc.calcSum(start, end);
   }
}

public class ParallelTest {

  public static void main(String[] args) throws InterruptedException {

      int start = 1;
      int end = 100000;

      Calculation calc = new Calculation();
      CalculatorThread ct1 = new CalculatorThread(start, end/2 , calc);
      CalculatorThread ct2 = new CalculatorThread( (end/2) + 1, end, calc);

      ct1.start();
      ct2.start();

      ct1.join();
      ct2.join();

      System.out.println(calc.getTotal());
  }
}

最佳答案

对共享可变状态的非同步访问通常不会很顺利。

在您的Calculation calc 中,有一个可变变量long total。当您启动线程时:

  CalculatorThread ct1 = new CalculatorThread(start, end/2 , calc);
  CalculatorThread ct2 = new CalculatorThread( (end/2) + 1, end, calc);

您在这两个线程之间共享 calc 的可变状态。 calc 中没有任何同步,因此线程只会在随机时间间隔内互相破坏内存。

这是一个工作版本:

class ParallelSum {
  public static long calcSum(long start, long end) {
      long total = 0;
      for(long i = start; i < end; i++) {
          total += i;
      }
      return total;
  }

  public static class CalculatorThread extends Thread {
     private long result = 0;
     private long start;
     private long end;
     public CalculatorThread(long start, long end) {
         this.start = start;
         this.end = end;
     }
     @Override
     public void run() {
         result = calcSum(start, end);
     }
     public long getResult() {
         return result;
     }
  }

  public static void main(String[] args) throws InterruptedException {
    int start = 1;
    int end = 100000;
    int endExcl = end + 1;

    CalculatorThread ct1 = new CalculatorThread(start, endExcl/2);
    CalculatorThread ct2 = new CalculatorThread(endExcl / 2, endExcl);

    ct1.start();
    ct2.start();

    ct1.join();
    ct2.join();

    System.out.println(ct1.getResult() + ct2.getResult());
  }
}

输出:

5000050000

附加说明:始终使用 [inclusive, exclusive) 范围索引。这大大降低了差一错误的可能性。此外,我用一个方法替换了 Calculation 类:方法内部的局部变量不会出错,可变状态越少越好。

关于使用 join() 的 Java 多线程程序在计算相邻数字之和时给出了错误的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50556922/

相关文章:

java - 打印并行运行的多个 SSH 命令的输出

java - Tomcat 第一次响应慢

java - (GridWorld) World 的 setGrid() 无法正确重画?

multithreading - 日志记录和同步

android - recyclerview 中不正确的线程错误导致的 Realm 访问

go - fatal error - 所有 Goroutines 都在 sleep !僵局

c++ - 如何从 dispatch_apply (GCD) 循环写入数组?

java - 关于选择算法

java - Spring 通配符不起作用

multithreading - 有没有办法在服务器级别强制停止 nifi 处理器?