我正在尝试用方法练习同步关键字。
我编写了以下代码:
加法器类:
public class Adder implements Runnable{
Counter counter;
Adder(Counter counter){
this.counter = counter;
}
public void run() {
for (int i=0; i<100; i++)
counter.setCount(counter.getCount()+1);
}
}
计数器类别:
public class Counter {
private int count = 0;
public synchronized void setCount(int val){
count = val;
}
public synchronized int getCount(){
return count;
}
}
主要:
public class main {
public static void main(String[] args) {
Counter counter = new Counter();
Adder adder = new Adder(counter);
Thread t1 = new Thread(adder);
Thread t2 = new Thread(adder);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(counter.getCount());
}
}
我预计其输出为 200,但它不是确定性的(理论上,可以是 0-200 之间的任何值)。我怀疑问题是我正在使用内联的 getter 和 setter,即
counter.setCount(counter.getCount()+1);
由于某种原因,这“破坏”了我试图通过同步实现的互斥,但我不明白为什么。
我用 count++ 实现了 1 的加法,如下所示:
public synchronized void add1(){
count++;
}
这有效,也许是因为这样我只使用一个函数而不是两个内联函数。 您能解释一下为什么第一个实现不起作用吗?
最佳答案
调用 getter 和后续调用 setter 是两个独立的操作。 “设置 getter 的结果加一”在这里不是原子的。因此,您完全可以有两个 get 返回相同的值,并且两组相同的值加一。
假设计数
为100
。您有两个线程调用 getter,都获得 100。然后它们都调用 setter,设置 101。所以计数器现在是 101,而不是 102 - 并且两个线程都“在那里”。
因此结果是不确定的,取决于两个线程获取/设置操作的实际顺序。
关于java - 调用同步的 getter 和 setter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40963470/