我正在尝试使用方法练习synchronize关键字。
我写了以下代码:
加法类:
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 inline,即
counter.setCount(counter.getCount()+1);
由于某种原因,这&#34;打破&#34;我试图通过同步实现的互斥,但我不明白为什么。
我用计数++实现了1的加法:
public synchronized void add1(){
count++;
}
这很有效,也许是因为这种方式我只使用一个函数而不是两个内联函数。 你能解释为什么第一个实现不起作用吗?
答案 0 :(得分:1)
<div disabled="disabled" id="someDisplay1" style="display: none;">
<div class="form-group">
<label>Display 1</label>
<input name="TextBox1" style="display: none;" type="text" value="" />
</div>
</div>
不是原子,它涉及3个步骤:
(1)读取counter.setCount(counter.getCount()+1);
(2)在count
(3)写下count
在第一种方法中,您将独立获取锁,即,在一个线程的count
和get
调用之间,将存在其他线程的干扰。因此,您无法保证第一个线程读取值与写入时相同。
在第二种方法中,您持有锁并执行上述所有3个步骤,因此您不会发现任何问题。
此外,您还可以使用threadsafe AtomicInteger类来解决您的问题。
答案 1 :(得分:1)
调用getter并随后调用setter是两个独立的操作。 &#34;设置getter的结果加一个&#34;这里不是原子的。所以你可能完全有两个返回相同的值,两个相同的值增加一个。
假设count
为100
。你有两个调用getter的线程调用,都得到100.然后他们都调用setter,设置101.所以计数器现在是101,而不是102 - 并且两个线程&#34;都在那里&#34;已经
所以结果是非确定性的,取决于两个线程的get / set操作的实际顺序。