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

我写了这个简单的多线程程序来添加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());
  }
}
最佳答案
对共享可变状态的非同步访问通常不顺利.

在您的计算计算中,有一个可变变量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

附加说明:始终使用[包含,独占]范围索引.这大大降低了逐个出错的几率.此外,我已经通过一种方法替换了Calculation类:在方法内部,局部变量没有任何问题,并且可变状态越少越好.

转载注明原文:使用join()的Java多线程程序在计算相邻数字的总和时给出了错误的结果 - 代码日志