14

与えられた:

public class TestSeven extends Thread {

private static int x;

public synchronized void doThings() {
    int current = x;
    current++;
    x = current;
}

public void run() {
    doThings();
  }
}

正しい説明はどれですか?

A.コンパイルは失敗します。

B.実行時に例外がスローされます。

C. run()メソッドを同期すると、クラスはスレッドセーフになります。

D.変数「x」のデータは同時アクセスの問題から保護されています。

E. doThings()メソッドを静的として宣言すると、クラスはスレッドセーフになります。

F.synchronized(new Object()){}ブロックのdoThings()内のステートメントをラップすると、クラスはスレッドセーフになります。

そのクラスをスレッドセーフにするために、doThings()を同期済みとしてマークするだけでは不十分ですか?正解はDですが、この質問のモデルの答えはEですが、理由がわかりません。

4

5 に答える 5

19

E. doThings()メソッドを静的として宣言すると、クラスはスレッドセーフになります。

それはちょっとトリッキーな答えです。メソッドはすでに同期されていますが、インスタンス上にありますが、状態は静的フィールド、つまりクラスにあります。それを作成することstatic synchronizedは確かに正しい答えです。なぜなら、それは(意味のない)インスタンスではなく、クラスで同期するからです。

D.変数「x」のデータは同時アクセスの問題から保護されています。

private static int x;

これは静的変数です。これはクラスのすべてのインスタンスで共有されるため、完全な使い捨てダミーオブジェクトで同期するFが役に立たないのと同じように、個々のインスタンスで同期することは役に立ちません。

于 2012-09-06T03:25:25.237 に答える
12

言語仕様によると:

同期メソッドは、実行前にモニター(§17.1)を取得します。

クラス(静的)メソッドの場合、メソッドのクラスのClassオブジェクトに関連付けられたモニターが使用されます。

インスタンスメソッドの場合、これに関連付けられたモニター(メソッドが呼び出されたオブジェクト)が使用されます。

これは、指定したコードで、synchronizedキーワードを指定すると、メソッドthisの本体を実行する前に、メソッドがロックオンを取得することを意味します。ただし、それxはへの更新がアトミックstaticであることを保証するものではないためです。x(クラスの別のインスタンスは、同期領域に入り、同時に更新を実行する可能性があります。これはthis、値が異なり、ロックが異なるためです。)

ただし、doStuffstaticを宣言すると、メソッドへのすべての呼び出しが同じロック(上のロック)を取得するClassため、メソッド本体での相互排除が保証されます。

仕様は実際にそれを綴っています:

class A {
    static synchronized void doSomething() {
        // ...
    }
}

文字通りと同じものです

class A {
    static void doSomething() {
        synchronized(A.class) {
            // ...
        }
    }
}

同様に:

class B {
    synchronized void doSomething() {
        // ...
    }
}

文字通りと同じものです

class B {
    void doSomething() {
        synchronized (this) {
            // ...
        }
    }
}
于 2012-09-06T03:27:11.807 に答える
6

doThings()メソッドを同期することにより、特定のTestSevenオブジェクトのロックを保持しています。ただし、クラスの静的変数は、オブジェクト自体の特定のインスタンスに属していません。それらはClassオブジェクトに属していますTestSeven.class。だから、どちらかのために行くことができます

synchronized (TestSeven.class){
    int current = x;
    current++;
    x = current;
}

物事をやり過ぎているインスタンスロック内のクラスロックを取得しているdoThings()メソッド内。したがって、メソッドを静的としてマークして、Classオブジェクトのロックのみを取得するようにすることができます。

于 2012-09-06T03:27:20.697 に答える
1

他のスレッドがメソッドの実行と同時に変更する可能性があるためxです。作ることはこれを止めます。staticdoThingsdoThings static

于 2012-09-06T03:58:50.090 に答える
-6

正解はDであることに同意します。doThings()をstaticとして設定し、synchronizedキーワードを削除すると、50個のTestSevenスレッドを起動するだけで、x値が正しくなくなる可能性があるため、Eは正しくありません。

注:私はここで間違っていました。静的な同期メソッドが実際にはクラス自体ではなくインスタンスをロックモニターとして使用するという点を見逃しました。

于 2012-09-06T03:29:14.587 に答える