一、JAVAスレッドの実行メモリモデル【JAVAメモリモデル】について
7752 ワード
プログラム、コレクションはあくまでメモリデータの操作であり、計算の結果を永続する.論争
JAVAで実行する最小単位はスレッドである.JVMは各CPU、オペレーティングシステム等の差異を実現する.スレッドの実行モデルは、最終的に抽象的に次のように見ることができます.
各スレッドには独自のwork memoryがあり、main memoryを共有しています.
JMMの主な問題は以下の通りである.
原子性、原子レベルの操作、各スレッドの実行時は互いに独立しており、volatileと宣言されていない変数も独立しているが、work memoryとmain memoryの同期が行われる.
可視性、スレッド間の通信.すなわち、メインメモリの変数が表示され、work memoryからmain memoryに値を同期してスレッド間の通信を行い、synchronizeまたはvolatile信頼性を通過する.
秩序性、ここでは主に主なメモリの秩序を読み取り、書き込み、同期するために、スレッドの操作は一般的に
read and loadは、プライマリメモリから現在のワークメモリuse and assign実行コードに変数をコピーし、共有変数値store and writeを変更してワークメモリデータでプライマリメモリ関連コンテンツをリフレッシュする
ここでread and loadとstore and writeはJVMによって複数回実行されます
1,各スレッドで実行される変数はmain memoryのcopyからキャッシュに格納される.
メモリに追加され、プライマリメモリに同期されていないなど、共通の同時発生の問題.
しゅつりょく
ここでは、読み書きがプライマリメモリにタイムリーに同期されていないため、予想値100000未満であり、同期ロックが解放されると正常になります.
第2スレッドの実行が完了すると常に正確な計算値を出力し、原理はsynchronizeキーワードを見る.
2,JAVA呼び出しコードの順序は無秩序である.(DCLなどの問題)
一、bad実践、変数スレッド通信に頼って、これは再現しにくいが、Nパスを実行したのは正しいか、JVMの気持ちの問題にかかって、コードは以下の通りである.
コード出力が0に等しい場合があります.メソッドtest 4 SortRun()では、実行の順序が一定ではないため
二、bad実践、DCLの問題、ここで最もよく見られるdouble checked load(DCL)問題を引き出したのも、無秩序によるものである.
関連資料はたくさんありますが、実は
res = new Resource();
とみなす
Resource()
res=Resourceアドレス参照;
これは正しく実行される順序です.無秩序の原因は
res=Resourceアドレス参照;
Resource()
だから他はresを手に入れた!=null、実行しました.構造関数は全然実行されていません.
三、bad実践、単例モデル
これはDCLと似ていますJAva Singletonのいくつかの方式の解析(本当に元の帖が見つからないで、BSの下で転載して住所を貼らない)
もちろん最後のvolatileは可能です.volatileは毎回メインメモリの最新の値を読むからです.
関連キーワード
synchronize 1,monitor,2を取得して掛け,main memory copyの最新値3から実行4,work memory copyの最新値からmain memory 5までmonitorを解放する
final
可変ではなく、初期化時にのみ値を割り当てることができます.
しかし、非静的は構造方法に値を割り当てることができ、適用時に順序に注意し、以下のようにfinal変数を呼び出すことも可変になる.
次のコードで証明します.
package org.benson;/** * TODO to share the java load class sort * @author Benson QQ 107966750 * */class Base{ public Base() { System.out.println("init base,the variableA is "+((Child)this).variableA); } public void display(){ System.out.println("display in base,the variableA is "+((Child)this).variableA); }}class Child extends Base{ final int variableA; public Child(){ variableA=100; System.out.println("init child,the variableA is "+this.variableA); this.display(); }}public class Test4Sort { public static void main(String[] args) { new Child(); }}
結果は次のとおりです.
init base,the variableA is 0init child,the variableA is 100display in base,the variableA is 100
これでfinal値も可変になります
JAVAの初期化手順base and child class adress,static--> base class variable-->base class constructor-->child class variable-->child class constructor
volatile
スレッドでは、読み取りと書き込みは原子的であり、volatileのベストプラクティスはsynchronizeで書き込みをロックすること(または現在のvolatileの値に依存しない書き込みを使用すること)であり、読み取りはロックを使用せずに最新の値を保証することができ、共有ロックの実装と同様に
1,保証はスレッドの可視性,すなわち毎回得られるのは最新値であり,明らかに書き込みは保証されないためカウンタはできない.
2、もし1つのスレッドの中で読み書きが同時に発生するならば、それは書くことが先に読むことを保証することができて、例えばa=new instance();まずinstance()を初期化してaに値を割り当て、完全なinstanceを返すことを保証できます.
1つのスレッドの書き込みが少なく、1つのスレッドが読み取り続けると、変数がvolatileされ、最新の値が読み出されることが保証されます(ただし、書き込みは現在の値に依存しない必要があります).この場合はsynchronizeと同時に使用することが考えられます.ConcurrentHashMap類から高同時プログラムの設計構想を学ぶ【JDKソースコードに深く入り込む】参照
参考資料
二重チェックロックおよび単一モード
Javaメモリモデル(投稿が見つからない)
Javaマルチスレッドの発展の概要
Javaマルチスレッドと同時プログラミングのテーマ
JAVAで実行する最小単位はスレッドである.JVMは各CPU、オペレーティングシステム等の差異を実現する.スレッドの実行モデルは、最終的に抽象的に次のように見ることができます.
各スレッドには独自のwork memoryがあり、main memoryを共有しています.
JMMの主な問題は以下の通りである.
原子性、原子レベルの操作、各スレッドの実行時は互いに独立しており、volatileと宣言されていない変数も独立しているが、work memoryとmain memoryの同期が行われる.
可視性、スレッド間の通信.すなわち、メインメモリの変数が表示され、work memoryからmain memoryに値を同期してスレッド間の通信を行い、synchronizeまたはvolatile信頼性を通過する.
秩序性、ここでは主に主なメモリの秩序を読み取り、書き込み、同期するために、スレッドの操作は一般的に
read and loadは、プライマリメモリから現在のワークメモリuse and assign実行コードに変数をコピーし、共有変数値store and writeを変更してワークメモリデータでプライマリメモリ関連コンテンツをリフレッシュする
ここでread and loadとstore and writeはJVMによって複数回実行されます
1,各スレッドで実行される変数はmain memoryのcopyからキャッシュに格納される.
メモリに追加され、プライマリメモリに同期されていないなど、共通の同時発生の問題.
package org.benson.threadgroup;
import java.util.concurrent.CountDownLatch;
/**
* TODO share the thread memory operation
* @author Benson QQ 107966750
*
*/
class Data{
public static int count=0;
}
public class TreadTest extends Thread{
private CountDownLatch countDCH=null;
public TreadTest(CountDownLatch countDCH) {
this.countDCH=countDCH;
}
@Override
public void run() {
for(int i=0;i<10000;i++)
// synchronized (Data.class) {
Data.count++;
// }
countDCH.countDown();
}
public static void main(String[] args) throws InterruptedException {
final int threadSize=10;
CountDownLatch countDCH=new CountDownLatch(threadSize);
for(int i=0;i<threadSize;i++)
new Thread(new TreadTest(countDCH)).start();
countDCH.await();
System.out.println(Data.count);
}
}
しゅつりょく
91660
ここでは、読み書きがプライマリメモリにタイムリーに同期されていないため、予想値100000未満であり、同期ロックが解放されると正常になります.
第2スレッドの実行が完了すると常に正確な計算値を出力し、原理はsynchronizeキーワードを見る.
2,JAVA呼び出しコードの順序は無秩序である.(DCLなどの問題)
一、bad実践、変数スレッド通信に頼って、これは再現しにくいが、Nパスを実行したのは正しいか、JVMの気持ちの問題にかかって、コードは以下の通りである.
package org.benson.threadgroup;
/**
* TODO share load variable sort
* @author Benson QQ107966750
*
*/
class Process4SortA{
public int variableA=0;
public Process4SortA() {
variableA=100;
}
}
class Process4SortB extends Thread{
public boolean startFlag=false;
public int variableA;
public void test4SortRun(){
//do something another stuff
variableA=100;
startFlag=true; //maybe will process this code before the variableA=100
}
@Override
public void run() {
while(true){
if(startFlag){
System.out.println(variableA);
//do something another stuff
break;
}
}
}
}
public class TreadTestSort {
public static void main(String[] args) throws Exception {
Process4SortB proB=new Process4SortB();
proB.start();
proB.test4SortRun();
}
}
コード出力が0に等しい場合があります.メソッドtest 4 SortRun()では、実行の順序が一定ではないため
二、bad実践、DCLの問題、ここで最もよく見られるdouble checked load(DCL)問題を引き出したのも、無秩序によるものである.
class Foo {
private Resource res = null ;
public Resource getResource() {
if (res == null )
res = new Resource();
return res;
}
}
関連資料はたくさんありますが、実は
res = new Resource();
とみなす
Resource()
res=Resourceアドレス参照;
これは正しく実行される順序です.無秩序の原因は
res=Resourceアドレス参照;
Resource()
だから他はresを手に入れた!=null、実行しました.構造関数は全然実行されていません.
三、bad実践、単例モデル
これはDCLと似ていますJAva Singletonのいくつかの方式の解析(本当に元の帖が見つからないで、BSの下で転載して住所を貼らない)
もちろん最後のvolatileは可能です.volatileは毎回メインメモリの最新の値を読むからです.
関連キーワード
synchronize 1,monitor,2を取得して掛け,main memory copyの最新値3から実行4,work memory copyの最新値からmain memory 5までmonitorを解放する
final
可変ではなく、初期化時にのみ値を割り当てることができます.
しかし、非静的は構造方法に値を割り当てることができ、適用時に順序に注意し、以下のようにfinal変数を呼び出すことも可変になる.
次のコードで証明します.
package org.benson;/** * TODO to share the java load class sort * @author Benson QQ 107966750 * */class Base{ public Base() { System.out.println("init base,the variableA is "+((Child)this).variableA); } public void display(){ System.out.println("display in base,the variableA is "+((Child)this).variableA); }}class Child extends Base{ final int variableA; public Child(){ variableA=100; System.out.println("init child,the variableA is "+this.variableA); this.display(); }}public class Test4Sort { public static void main(String[] args) { new Child(); }}
結果は次のとおりです.
init base,the variableA is 0init child,the variableA is 100display in base,the variableA is 100
これでfinal値も可変になります
JAVAの初期化手順base and child class adress,static--> base class variable-->base class constructor-->child class variable-->child class constructor
volatile
スレッドでは、読み取りと書き込みは原子的であり、volatileのベストプラクティスはsynchronizeで書き込みをロックすること(または現在のvolatileの値に依存しない書き込みを使用すること)であり、読み取りはロックを使用せずに最新の値を保証することができ、共有ロックの実装と同様に
1,保証はスレッドの可視性,すなわち毎回得られるのは最新値であり,明らかに書き込みは保証されないためカウンタはできない.
2、もし1つのスレッドの中で読み書きが同時に発生するならば、それは書くことが先に読むことを保証することができて、例えばa=new instance();まずinstance()を初期化してaに値を割り当て、完全なinstanceを返すことを保証できます.
1つのスレッドの書き込みが少なく、1つのスレッドが読み取り続けると、変数がvolatileされ、最新の値が読み出されることが保証されます(ただし、書き込みは現在の値に依存しない必要があります).この場合はsynchronizeと同時に使用することが考えられます.ConcurrentHashMap類から高同時プログラムの設計構想を学ぶ【JDKソースコードに深く入り込む】参照
参考資料
二重チェックロックおよび単一モード
Javaメモリモデル(投稿が見つからない)
Javaマルチスレッドの発展の概要
Javaマルチスレッドと同時プログラミングのテーマ