use*_*321 5 java concurrency multithreading java-memory-model java-threads
我编写了这个简单的多线程程序,将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());
}
}
Run Code Online (Sandbox Code Playgroud)
对共享可变状态的非同步访问通常不会顺利进行。
在您的中Calculation calc,有一个可变变量long total。当您启动线程时:
CalculatorThread ct1 = new CalculatorThread(start, end/2 , calc);
CalculatorThread ct2 = new CalculatorThread( (end/2) + 1, end, calc);
Run Code Online (Sandbox Code Playgroud)
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());
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
5000050000
Run Code Online (Sandbox Code Playgroud)
附加说明:始终使用[inclusive, exclusive)范围索引。这极大地降低了出现相差一错误的机会。另外,我用方法替换了Calculation类:方法内部的局部变量不会出错,并且可变状态越少越好。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |