鉴于此Java代码:
class Account {
private Integer number = 0;
public synchronized void setNumber(Integer number) {
this.number = number;
}
public synchronized Integer getNumber() {
return number;
}
}
class Client extends Thread {
Account account;
public Client(Account account) {
this.account = account;
}
public void run() {
for (int i = 1; i <= 1000; i++) {
account.setNumber(account.getNumber() + 1);
}
}
}
public class Run {
public static void main(String[] args) throws Exception {
Account account = new Account();
Client one = new Client(account);
Client two = new Client(account);
one.start();
two.start();
one.join();
two.join();
System.out.println("Exiting main");
System.out.println("account number value: " +account.getNumber());
}
}
主方法完成后number
的值是多少?是2000还是不到2000?我得到的不到2000.两个线程如何同时从getNumer()
调用setNumber()
或run()
,因为每个线程都是同步的?
答案 0 :(得分:8)
仔细考虑下一节中会发生什么。
account.setNumber(account.getNumber() + 1);
尽管两种方法是分开同步的,但整体操作却不是。
答案 1 :(得分:5)
该数字可能小于或等于2000,但从不高。请考虑每个“set”和“get”数字函数是单独同步,但它们不会同步在一起。这意味着线程之间的竞争条件可以“跳过”对组合“增量”效果的调用。
考虑两个线程之间可能的调用序列:
number Thread1 Thread2
0 get => 0 -
- - get => 0
- - incr => 1
1 - set => 1
- incr => 1 -
1 set => 1 -
请注意,每个线程的数字为零,单独递增,然后设置数字1。两个线程都认为它们增加了数字但是它们对set / get的调用是交错的,所以其中一个被有效地跳过了。
相比之下,尝试在名为increment()
的Account类中编写第三个同步方法,该方法以原子方式执行get / increment / set序列,并且看到您将始终获得数字2000。