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

时间:2012-05-12 06:49:44

标签: java multithreading

鉴于此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(),因为每个线程都是同步的?

2 个答案:

答案 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。