二重ロックの単一モードを深く研究する
2804 ワード
前言
以前の単例モードのブログでは、よく見られるいくつかの単例モードについて紹介しましたが、そのうちの1つ、二重チェックロックが実現した単例モードについては、簡単な数行のコードほど簡単ではありません.その中に含まれている深い意味は実は重要です.ここでは、いくつかの説明をします.
--------------------------------------------------------------------------------------------
(一)完璧に見える二重ロック単例モード
二重検査が存在するため,同期のオーバーヘッドを低減し,完璧に見え,同時環境での欠点を解決した.しかし、注意してください.私がマークした行のコードは、実は並べ替えという問題があります.
この行のコードは次の3行の偽コードになります.
1.memory=allocate()/オブジェクトのメモリ領域の割り当て
2.ctorInstance//オブジェクトの初期化
3.person=memory//personが割り当てたばかりのメモリアドレスを設定する
上の3行のコードは実は2-3の間で、1つの並べ替えの問題が存在して、現れる可能性があって、このような情況は2つの情況に分けて討論します
①単線での
1.memory=allocate()/オブジェクトのメモリ領域の割り当て
2.person=memory//personが割り当てたばかりのメモリアドレスを設定する
3.ctorInstance//オブジェクトの初期化
このような場合、実際には最終結果には影響しませんが、マルチスレッドの場合は異なります.
②マルチスレッドでの
時間
スレッドA
スレッドB
t1
1.オブジェクトのメモリ容量を割り当てる
t2
2.personメモリポインタの設定
t3
1.personが空かどうかを判断する
t4
2.personが空ではないため、スレッドBはpersonが参照するオブジェクトにアクセスする
t5
3.オブジェクトの初期化
t6
4.personが指すオブジェクトへのアクセス
このように,スレッドBが初期化されていないオブジェクトにアクセスすると,問題が露呈する.
だから、この問題を解決するために、私たちは2つの解決方法を考えることができます.
1.2と3の並べ替えは許可されていません
2.2と3の並べ替えは許可されていますが、他のスレッドはこの並べ替えを見ることは許可されていません.
第一に、上記の二重ロックの単例モードのアップグレード版があります.
(二)キーワードが1つしか追加されていないダブルロック単例モード
volatileキーワードを1つ追加するだけで問題が解決し、宣言オブジェクトがvolatileである場合、上の3行のコード間の再ソートがマルチスレッド環境では禁止されます.
volatileキーワードのプロパティは2つあります.
1.可視性を保証し、原子性を保証しないa.volatile変数を書くと、JMMはスレッドのローカルメモリの変数を強制的にメインメモリにリフレッシュするb.この書き込みは他のスレッドのキャッシュを無効にする.2.命令再並べ替え禁止とは、コンパイラおよびプロセッサがプログラム性能を最適化するために命令シーケンスを並べ替える手段である.
このことから,たった一つのキーワードでこの問題を解決したことがわかる.
----------------------------------------------------------------------------------------
上の方法は並べ替えの問題の解決方法に対して、第1種を採用して、それでは第2種に対して、私達は前に私が書いたあのような静的な内部クラスの方法を採用して解決することができて、コードは前のブログに行って見ることができます
構想は:2-3行のコードの再ソートを許可するが、非構造スレッド(別のスレッド)がこの再ソートを見ることを許可しない.JVM内部のロックメカニズムにより、複数のインスタンスが作成されないことを保証し、マルチスレッドの問題を巧みに回避します.
以前の単例モードのブログでは、よく見られるいくつかの単例モードについて紹介しましたが、そのうちの1つ、二重チェックロックが実現した単例モードについては、簡単な数行のコードほど簡単ではありません.その中に含まれている深い意味は実は重要です.ここでは、いくつかの説明をします.
--------------------------------------------------------------------------------------------
(一)完璧に見える二重ロック単例モード
public class Person {
private static Person person;
private Person(){}
public static Person getInstance(){
if(person == null){//
synchronized (Person.class){//
if(person == null)//
person = new Person();// ,
}
}
return person;
}
}
二重検査が存在するため,同期のオーバーヘッドを低減し,完璧に見え,同時環境での欠点を解決した.しかし、注意してください.私がマークした行のコードは、実は並べ替えという問題があります.
この行のコードは次の3行の偽コードになります.
1.memory=allocate()/オブジェクトのメモリ領域の割り当て
2.ctorInstance//オブジェクトの初期化
3.person=memory//personが割り当てたばかりのメモリアドレスを設定する
上の3行のコードは実は2-3の間で、1つの並べ替えの問題が存在して、現れる可能性があって、このような情況は2つの情況に分けて討論します
①単線での
1.memory=allocate()/オブジェクトのメモリ領域の割り当て
2.person=memory//personが割り当てたばかりのメモリアドレスを設定する
3.ctorInstance//オブジェクトの初期化
このような場合、実際には最終結果には影響しませんが、マルチスレッドの場合は異なります.
②マルチスレッドでの
時間
スレッドA
スレッドB
t1
1.オブジェクトのメモリ容量を割り当てる
t2
2.personメモリポインタの設定
t3
1.personが空かどうかを判断する
t4
2.personが空ではないため、スレッドBはpersonが参照するオブジェクトにアクセスする
t5
3.オブジェクトの初期化
t6
4.personが指すオブジェクトへのアクセス
このように,スレッドBが初期化されていないオブジェクトにアクセスすると,問題が露呈する.
だから、この問題を解決するために、私たちは2つの解決方法を考えることができます.
1.2と3の並べ替えは許可されていません
2.2と3の並べ替えは許可されていますが、他のスレッドはこの並べ替えを見ることは許可されていません.
第一に、上記の二重ロックの単例モードのアップグレード版があります.
(二)キーワードが1つしか追加されていないダブルロック単例モード
public class Person {
private static volatile Person person;
private Person(){}
public static Person getInstance(){
if(person == null){
synchronized (Person.class){
if(person == null)
person = new Person();
}
}
return person;
}
}
volatileキーワードを1つ追加するだけで問題が解決し、宣言オブジェクトがvolatileである場合、上の3行のコード間の再ソートがマルチスレッド環境では禁止されます.
volatileキーワードのプロパティは2つあります.
1.可視性を保証し、原子性を保証しないa.volatile変数を書くと、JMMはスレッドのローカルメモリの変数を強制的にメインメモリにリフレッシュするb.この書き込みは他のスレッドのキャッシュを無効にする.2.命令再並べ替え禁止とは、コンパイラおよびプロセッサがプログラム性能を最適化するために命令シーケンスを並べ替える手段である.
このことから,たった一つのキーワードでこの問題を解決したことがわかる.
----------------------------------------------------------------------------------------
上の方法は並べ替えの問題の解決方法に対して、第1種を採用して、それでは第2種に対して、私達は前に私が書いたあのような静的な内部クラスの方法を採用して解決することができて、コードは前のブログに行って見ることができます
構想は:2-3行のコードの再ソートを許可するが、非構造スレッド(別のスレッド)がこの再ソートを見ることを許可しない.JVM内部のロックメカニズムにより、複数のインスタンスが作成されないことを保証し、マルチスレッドの問題を巧みに回避します.