SO で Java の同期に関する質問が出てくると、同期はsynchronized(this)
避けるべきだと熱心に指摘する人がいます。代わりに、プライベート参照のロックが望ましいと主張します。
挙げられる理由としては次のようなものがあります。
- 悪意のあるコードがロックを盗む可能性があります(これは非常に人気があり、「偶然」のバリエーションもあります)
- 同じクラス内のすべての同期メソッドはまったく同じロックを使用するため、スループットが低下します。
- あなたは(不必要に)情報を公開しすぎています
私を含め他の人々は、これはsynchronized(this)
よく使われる慣用句であり(Java ライブラリでも)、安全でよく理解されていると主張しています。バグがあり、マルチスレッド プログラムで何が起こっているのか分からないからといって、これを避けるべきではありません。言い換えれば、適用できる場合は、使用してください。
ロックオンを回避することが望ましいが、this
同時にsynchronized(this)
機能も果たすような実際の例(foobar 関連のものは除く)をいくつか見てみたいと思っています。
したがって、常にsynchronized(this)
これを回避し、プライベート参照のロックに置き換える必要がありますか?
詳細情報(回答が提供されると更新されます):
- インスタンスの同期についてお話します
- 暗黙の(
synchronized
メソッド)と明示的な形式の両方synchronized(this)
が考慮される - Bloch やこのテーマに関する他の権威を引用する場合は、気に入らない部分を省略しないでください (例: Effective Java のスレッド セーフティに関する項目:通常はインスタンス自体のロックですが、例外もあります)。
- 提供されるもの以外のロックの粒度が必要な場合は
synchronized(this)
、synchronized(this)
適用できないので、それは問題ではありません。
ベストアンサー1
それぞれのポイントを個別に説明します。
-
悪意のあるコードがロックを盗む可能性があります (これは非常に一般的ですが、「偶然」のバリエーションもあります)
私は、偶然ののほうが心配です。つまり、 のこの使用は、
this
クラスの公開されたインターフェースの一部であり、文書化される必要があるということです。場合によっては、他のコードがロックを使用できるようにすることが望まれます。これは、次のような場合に当てはまりますCollections.synchronizedMap
(javadoc を参照)。 -
同じクラス内のすべての同期メソッドはまったく同じロックを使用するため、スループットが低下します。
これはあまりにも単純な考え方です。単に取り除くだけでは
synchronized(this)
問題は解決しません。スループットの適切な同期には、さらに検討が必要です。 -
あなたは(不必要に)情報を公開しすぎています
これは #1 のバリエーションです。 の使用は
synchronized(this)
インターフェースの一部です。 これを公開したくない/公開する必要がない場合は、使用しないでください。