このコードは安全にロックされているのですか?
-
29-10-2019 - |
質問
私たちのアプリのコードを見ています。ダブルチェックロック「。私たちがしていることに似たサンプルコードをいくつか書きました。
誰もがこれがダブルチェックロックをどのように経験できるかを見ることができますか?それとも安全ですか?
class Foo {
private Helper helper = null;
public Helper getHelper() {
Helper result;
synchronized(this) {
result = helper;
}
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
}
から借りた基本コード ウィキ.
解決
ダブルチェックロックの全体的なポイントは、高速パス(オブジェクトをインスタンス化する必要がない場合)が同期されていないことです。したがって、あなたが持っているものはロックを再確認していません。
壊れたダブルチェックロックを取得するには、最初の同期ブロックを取り除く必要があります。それからあなたは作る必要があります helper
それを修正するために揮発性。
他のヒント
それは不必要に複雑で、DCLを行う最も単純な「安全な」方法はそうです:
class Foo {
private volatile Helper helper = null;
private final Object mutex = new Object();
public Helper getHelper() {
if (helper == null) {
synchronized(mutex) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
}
ここでの重要なポイントは次のとおりです。
- 「幸せな」ケースでは、ヘルパーが既に割り当てられることを期待しているため、同期ブロックを入力することなく返品することができます。
- ヘルパーは、ヘルパーをいつでもスレッドで読み取ることができることをコンパイラーに知らせるために揮発性としてマークされており、読み取り /書き込みが再注文されないことが重要です。
- 同期されたブロックは、プライベートファイナル変数を使用して同期して、コードの別の領域が同期する場合の潜在的なパフォーマンスヒットを回避するために同期します
this
実例。
この部分は、標準のダブルチェックロックです。
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
最初の部分は、ダブルチェックされたロックパーツに対して何もしない役に立たない割り当てです。ヘルパーがnullの場合、とにかく実行されます。それは完全に効果がありません。
所属していません StackOverflow