这个多线程Java代码是如何工作的?

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

当主方法完成时,number的值是多少?是2000还是小于2000?我得到的答案是小于2000。如果每个线程都被同步,那么两个线程如何同时调用getNumber()setNumber()?请注意保留所有HTML标签。
2个回答

8
请仔细思考以下部分会发生什么。
account.setNumber(account.getNumber() + 1);

尽管这两种方法各自同步,但整个操作并没有同步。

不客气。如果您已经得到了问题的答案,您应该选择一个答案作为正确答案。 - Sridhar

5

数字可能小于或等于2000,但永远不会更高。请注意,每个“设置”和“获取”数字函数都是单独同步的,但它们不是一起同步的。这意味着线程之间存在竞争条件,可能会“跳过”对组合“增量”效果的调用。

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

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

请注意,每个线程都获得了数字0,分别进行递增,然后设置为数字1。两个线程都认为它们递增了该数字,但它们的set/get调用交错,因此其中一个被有效跳过。
相比之下,请尝试在Account类中编写第三个同步方法"increment()",它可以原子性地执行get/increment/set序列,并查看您将始终获得数字2000。

感谢Maerics回答我的问题。 - Vijay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接