web-dev-qa-db-ja.com

Java synchronizedメソッド

次のコードを検討してください。

public synchronized void onSignalsTimeout(List<SignalSpec> specs) {
    if (specs != null && specs.size() > 0) {
        for (SignalSpec spec : specs) {
            ParsedCANSignal timeoutedSignal = new ParsedCANSignal();
            SignalsProvider.getInstance().setSignal(spec.name, spec.parent.parent.channel, timeoutedSignal);
        }
    }
}

簡単な質問があります:スレッド1がonSignalsTimeoutメソッドを呼び出すと、スレッド2はそのメソッドでアクセスされるオブジェクトにアクセスできますか?

「同期」がこのメソッドへのアクセスまたはこのメソッドで使用されるすべてのオブジェクトへのアクセスのみをロックする場合、どこにも見つかりません。

36
arenaq

まず、synchronized methodsを忘れてください。いわゆる同期方法...

_synchronized AnyType foobar(...) {
    doSomething();
}
_

これを書く簡単な方法にすぎません:

_AnyType foobar(...) {
    synchronized(this) {
        doSomething();
    }
}
_

どちらの場合もmethodについて特別なことはありません。特別なのはsynchronized blockであり、同期ブロックが行うことは非常に簡単です。 JVMがこれを実行するとき:

_synchronized(foo) {
    doSomething();
}
_

最初に式fooを評価します。結果はオブジェクト参照でなければなりません。次に、オブジェクトをロックし、synchronizedブロックの本体を実行してから、オブジェクトのロックを解除します。

しかし、lockedはどういう意味ですか?あなたが思っているよりも少ないことを意味するかもしれません。 notは、他のスレッドがオブジェクトを使用できないようにします。オブジェクトのフィールドにアクセスしたり、フィールドを更新したりすることを妨げません。オブジェクトをロックすると、他のスレッドが同じオブジェクトを同時にロックするのを防ぐことができます。

スレッドAがsynchronized(foo) {...}に入ろうとするときに、スレッドBが既にfooをロックしている(同じsynchronizedブロックまたは別のブロック)場合、スレッドAはスレッドまで待機するように強制されますBはロックを解除します。


保護するためにsynchronizedブロックを使用しますdata

プログラムに、異なるstatesになる可能性のあるオブジェクトのコレクションがあるとします。いくつかの状態が意味をなすが、意味をなさない他の状態があると仮定します。-invalid状態。

一時的に無効な状態を作成せずに、スレッドが1つの有効な状態から別の有効な状態にデータを変更できないと仮定します。

状態を変更するコードをsynchronized(foo)ブロックに入れ、everyできるコードのブロックをsee同期ブロックに入れた場合同じオブジェクトfooをロックすると、他のスレッドが一時的な無効な状態を見るのを防ぐことができます。

92
Solomon Slow

はい、他のスレッドはメソッドで使用されるオブジェクトにアクセスできます。 synchronizedキーワードは、一度に複数のスレッドがメソッドのコードを実行できないことを保証します。

https://docs.Oracle.com/javase/tutorial/essential/concurrency/syncmeth.html から:

  • まず、同じオブジェクトで同期メソッドを2回呼び出してインターリーブすることはできません。 1つのスレッドがオブジェクトの同期メソッドを実行している場合、同じオブジェクトの同期メソッドを呼び出す他のすべてのスレッドは、オブジェクトで最初のスレッドが完了するまでブロック(実行を中断)します。
  • 第二に、同期メソッドが終了すると、同じオブジェクトの同期メソッドの以降の呼び出しとの発生前関係を自動的に確立します。これにより、オブジェクトの状態の変更がすべてのスレッドから見えるようになります。コンストラクターは同期できないことに注意してください。コンストラクターでsynchronizedキーワードを使用すると、構文エラーになります。コンストラクタの同期は意味がありません。なぜなら、オブジェクトを作成しているスレッドだけが、構築中にアクセスできるはずだからです。
8
Andrea Iacono

このコンテキストでは、synchronizedは、このメソッドと、クラスでsynchronizedとして同様にマークされた他のメソッドを同時にロックします。

5
Bathsheba