2

私は次のようなコードを持っています:

class OuterClass
{
   private final AtomicInteger count = new AtomicInteger(0);

   private class InnerClass extends TimerTask
   {
       public void run()
       {
            ......
            ......
            incremenetCount();
       }
   }

   public void doSomething()
   {
        .......
        .......
        incremenetCount();
   }

   private void incrementCount()
   {
      count.incrementAndGet();
   }
}

同期は実際には変数の周りで行われるため、内部クラスから呼び出すincrementCountことは、外部クラスの他の関数から呼び出すことと同じcountですか?

4

2 に答える 2

5

内部クラスからincrementAndCountを呼び出すことは、外部クラスの他の関数から呼び出すことと同じです[...]

はい、内部クラスからの呼び出しは、外部カウントからのincrementCount()呼び出しと同じです。incrementCount()

すべての非静的内部クラスには、それを囲むクラスのオブジェクトへの暗黙の参照があり、この参照を通じてincrementCount()呼び出されます。

(ただし、内部クラスが静的である場合、ストーリーは異なっていたでしょう。)

同期は実際には変数カウントの周りにあるので?

関係ない。内部クラスから呼び出すか外部クラスから呼び出すかに関係なく、同じメソッドが同じオブジェクトで呼び出されます。

于 2012-04-25T04:46:32.047 に答える
3

簡単に言えば、安全だということです。

理由を理解するために、これを見てみましょう:

class SomeClass {
    private final AtomicInteger count = new AtomicInteger(0);
    ...
    private void incrementCount() {
        count.incrementAndGet();
    }
}

これがスレッドセーフであるかどうかを判断するために考慮する必要がある2つの質問があります。

  1. のフェッチはcount適切に同期されていますか?はいと答えてください-countとして宣言されており、コンストラクターが完了すると、同期なしでフィールドを読み取ることができるfinalというルールがあります。final

  2. incrementAndGet()メソッドはスレッドセーフですか?はいと答えてください-AtomicIntegerクラスの仕様はそう言っています。

次に、内部クラスの場合を見てみましょう。内部クラスのインスタンスには、外部クラスのインスタンスへの非表示の最終参照があります。それで ...

    public void run() {
        incrementCount();
    }

これと同等です...

    private final OuterClass $outer;  // initialized by the constructor.
    ...
    public void run() {
        $outer.incrementCount();
    }

上記のポイント1の理由により、incrementCount()呼び出し自体はスレッドセーフです。また、のフェッチも暗黙的にフィールド$outerであるため、スレッドセーフです。final

于 2012-04-25T05:21:34.157 に答える