在Java中,为什么在synchronized
下面的代码中可以发表评论?因为加法几乎是原子的,因此错误或失败的可能性太小了?
public class AddInParallel {
public static void main(String[] args) {
class sumValue {
public int sum = 0;
sumValue() {}
public /*synchronized*/ void add(int i) {
sum += i;
}
}
// final makes sumValue visible to threads
final sumValue sum = new sumValue();
class Adder implements Runnable {
// used to distinguish threads
private int id;
Adder(int index) { id = index; }
public void run() { sum.add(1); }
}
// start threads
Thread[] threads = new Thread[1000];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Adder(i) {});
threads[i].start();
}
// wait for threads above to finish
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(sum.sum);
}
}
答案 0 :(得分:0)
正如Sotirios所建议的,如果我们在这里更改代码:
public /*synchronized*/ void add(int i) {
for (int j = 0; j < 1000; j++) {
sum += i;
}
}
到目前为止通常不会有一百万。因此需要同步。感谢。
答案 1 :(得分:0)
这种陈述不能总是被认为是原子的:
sum += i;
实际上,这一步涉及三个步骤(计算临时变量以存储sum
的当前值。)
即使volatile
变量声明中的sum
关键字在这种情况下也不相关(因为赋值基于其当前值)。
因此,您应该取消注释synchronized
关键字以启用锁定,以便在您的流程中不会遇到“意外”=&gt;意味着始终以1000
结束。
答案 2 :(得分:0)
synchronized
关键字不应该被注释掉。每当您从多个线程写入变量时,(至少)写入本身应该受到某种同步的保护 - synchronized
关键字,ReentrantReadWriteLock等。你在问题中提到,原因是个人写作不能保证是原子的。
虽然我怀疑此代码的目的是证明一点,但值得注意的是,您不需要使用锁来获取此代码;您可以使用AtomicInteger
代替int
sum
变量,而不使用任何类型的同步来获得正确的解决方案。
具体来说,您可以将public int sum
替换为public AtomicInteger sum=new AtomicInteger();
,将add()
的正文替换为:
public void add(int i) {
sum.addAndGet(i);
}
...现在你有一个无锁,正确的实现。 (您必须更新其他几个地方的代码才能打印并填充和运行,但我会将其作为练习留给读者。)