なぜシンクロナイズブロックで揮発性を使用するのですか?
-
12-12-2019 - |
質問
私はJavaのいくつかの例を見ました。そのインスタンスを初期化するブロックを確定しました。他の人には十分ではありませんか?
public class someClass {
volatile static uniqueInstance = null;
public static someClass getInstance() {
if(uniqueInstance == null) {
synchronized(someClass.class) {
if(uniqueInstance == null) {
uniqueInstance = new someClass();
}
}
}
return uniqueInstance;
}
.
事前にありがとうございました。
解決
最初のチェックが同期ブロック内であった場合は、その場合、その場合は十分です(ただし、変数が揮発性がない場合は別のスレッドが実行されていない場合は1つのスレッドは別のスレッドが実行されない場合があります)。揮発性のみでは、複数の操作を原子的に実行する必要があるため、十分ではありません。に注意してください!あなたがここで持っているものは、いわゆるダブルチェックロックです。NOREFERRER「>は確実に機能しない。Java 1.6以降に変更されたと思いますが、これはまだこの種のコードが危険になる可能性があります。
edit :変数が揮発性の場合、JDK 5以降は正しく機能します(私は以前に書き込まれたので6ではありません)が、JDK 1.4以前では期待どおりに機能しません。
他のヒント
これは二重チェックロックを使用しているため、if(uniqueInstance == null)
は同期部分内にないことに注意してください。
uniqueInstance
が揮発性でない場合は、synchronized
ブロックで実行されているスレッド以外に表示されていない部分的に構築されたオブジェクトで「初期化」されます。揮発性はこれを全部または何も何もない操作を行います。
同期ブロックを持っていない場合は、同時にこの時点にアクセスする2つのスレッドで終わることができます。
if(uniqueInstance == null) {
uniqueInstance = new someClass(); <---- here
.
とあなたは目的を破る2つのSomeclassオブジェクトを構築します。
厳密に言えば、あなたは揮発性を必要とせず、この方法はになっている可能性があります
public static someClass getInstance() {
synchronized(FullDictionary.class) {
if(uniqueInstance == null) {
uniqueInstance = new someClass();
}
return uniqueInstance;
}
}
.
しかし、それはGetInstance()を実行するすべてのスレッドの同期とシリアル化を招きます。
この記事揮発性の後ろ。
それはまた、 Java Memory Model 。)
同期ブロックを使用せずに同期を行うことができます。 揮発変数を使用する必要はありません... 揮発性メインメモリからの1つの変数を更新します 同期メインメモリからアクセスされたすべての共有変数を更新します。 だからあなたはあなたの要求に従ってそれを使うことができます。
私の2つのセントここに
フレンドこのコードの直感の素早い説明
if(uniqueInstance == null) {
synchronized(someClass.class) {
if(uniqueInstance == null) {
uniqueInstance = new someClass();
}
}
}
.
UniqueInstance== NULLを2回チェックする理由は、比較的遅い同期ブロックを呼び出すオーバーヘッドを減らすことです。いわゆるダブルチェックロック。
第2に、同期が使用する理由は理解しやすいため、同期ブロック原子内の2つの操作を行います。
最後の揮発性修正子は、すべてのスレッドが同じコピーを見ていることを確認して、同期ブロックの外側の最初のチェックでは、「同期化」の方法でユニークインスタンスの値が表示されます。 同期ブロックで。揮発性修正子がないと、1つのスレッドは値をUniqueiNSTANCEに割り当てることができますが、他のスレッドは最初のチェックで表示されない場合があります。(2番目のチェックはそれを見ると思われますが)