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 未満になっています。それぞれが同期されている場合、2 つのスレッドが同時にgetNumer()orsetNumber()を呼び出すにはどうすればよいでしょうか?run()

4

2 に答える 2

8

次のセクションで何が起こるかをよく考えてください。

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

両方の方法が個別に同期されますが、全体としての操作は同期されません。

于 2012-05-12T06:58:14.883 に答える
5

この数が 2000 以下になることはありますが、それ以上になることはありません。"set" および "get" 数値関数はそれぞれ個別に同期されますが、一緒には同期されないことを考慮してください。これは、スレッド間の競合状態により、結合された「インクリメント」効果への呼び出しが「スキップ」される可能性があることを意味します。

2 つのスレッド間の次の一連の呼び出しを考えてみましょう。

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

各スレッドは番号 0 を取得し、個別にインクリメントしてから番号 1 を設定することに注意してください。両方のスレッドは、数値をインクリメントしたと信じていましたが、set/get の呼び出しがインターリーブされたため、そのうちの 1 つが実質的にスキップされました。

increment()対照的に、取得/インクリメント/セット シーケンスをアトミックに実行するAccount クラスに 3 番目の同期メソッドを記述してみてください。常に 2000 という数値が取得されることがわかります。

于 2012-05-12T07:08:14.967 に答える