3

鉴于此 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());        
        }
    }

numbermain 方法完成时的值是多少?是2000还是2000以下?我得到的数量少于 2000。鉴于每个线程都是同步的,如何同时调用getNumer()setNumber()从两个线程调用?run()

4

2 回答 2

8

仔细思考下一节会发生什么。

account.setNumber(account.getNumber() + 1);

尽管这两种方法是单独同步的,但整个操作却不是。

于 2012-05-12T06:58:14.883 回答
5

该数字可能小于或等于 2000,但永远不会更高。考虑每个“set”和“get”数字函数分别同步它们不同步在一起。这意味着线程之间的竞争条件可能会“跳过”对组合“增量”效果的调用。

考虑两个线程之间可能的调用序列:

number  Thread1     Thread2
0       get => 0    -
-       -           get => 0
-       -           incr => 1
1       -           set => 1
-       incr => 1   -
1       set => 1    -

请注意,每个线程都获得数字零,分别递增,然后设置数字一。两个线程都认为他们增加了数字,但是他们对 set/get 的调用是交错的,因此其中一个被有效地跳过了。

相比之下,尝试在 Account 类中编写第三个同步方法,该方法以increment()原子方式执行 get/increment/set 序列,并看到您将始终获得数字 2000。

于 2012-05-12T07:08:14.967 回答