使用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类:在方法内部,局部变量没有任何问题,并且可变状态越少越好.
标签:java,multithreading,concurrency,java-memory-model,java-threads 来源: https://codeday.me/bug/20190527/1162093.html