Java同時(1)i++のスレッドセキュリティの問題
4969 ワード
1.問題背景条件マルチスレッド動作同一変数 ここではローカル変数ではありません.メンバー変数または静的変数に違いありません. PS:なぜローカル変数ではないのですか? は、複数のスレッドがローカル変数にアクセスする必要がある場合、匿名の内部クラス方式を使用して複数のスレッドを定義するなど、複数のスレッドをメソッドで定義する必要があります. 匿名内部クラスを使用してローカル変数を参照する場合、ローカル変数はfinalによって修飾される必要があります.これは変数のライフサイクルの問題が原因です. final修飾の変数は,intでもIntegerでも自己加算操作はできない.
2.スレッドセキュリティの問題の原因メモリ可視性 i++操作プロセス 3.メモリの可視性 Javaメモリモデル Aスレッド実行i++終了後、キャッシュ中の結果をメインメモリにタイムリーにリフレッシュしないと、Bスレッドがi++操作を開始し、結果がエラーになります. ソリューション:volatileキーワード修飾を使用します.
4.i++の操作手順
4.1. i++またはJavaコードの実際の操作手順をどのように知るか?
Javap逆コンパイルコードにより、バイトコードコマンドを分析します(アセンブリのような感じがします)
4.2. i++のバイトコードメンバー変数の自己増加操作 静的変数の自己増加動作 まとめ
4.3. スレッドセキュリティの問題
4.3.1.原理疑似コード
4.3.2.実行可能なテストコード
2.スレッドセキュリティの問題の原因
4.i++の操作手順
4.1. i++またはJavaコードの実際の操作手順をどのように知るか?
Javap逆コンパイルコードにより、バイトコードコマンドを分析します(アセンブリのような感じがします)
int i = 0;
i = i++;
// i = 0 ?
//
/*
0: iconst_0 // 0
1: istore_1 // int 1 i=0
2: iload_1 // 1 int tp = i
3: iinc 1, 1 // 1 1( )i = i+1
6: istore_1 // 1 i = tp
7: return
*/
4.2. i++のバイトコード
/*
0: aload_0 // , this
1: dup // ,
2: getfield #2 // , tp = i
5: iconst_1 // 1 tp2 = 1
6: iadd // int , tp3 = tp+tp2
7: putfield #2 // i=tp3
10: return
*/
/*
0: getstatic #5 // , tp = i
3: iconst_1 // 1 tp2 = 1
4: iadd // int , tp3 = tp+tp2
5: putstatic #5 // i=tp3
8: return
*/
//i++
tp = i //1
tp2 = tp+1 //2
i = tp2 //3
4.3. スレッドセキュリティの問題
4.3.1.原理疑似コード
// i, i++
static int i = 0;
// A
int tp1 = i; //1
int tp2 = tp1+1; //2
i = tp2; //3
// B
int tp3 = i; //4
int tp4 = tp3+1; //5
i = tp4; //6
// 1->2->3->4->5->6,
// 1->4->2->3->5->6,
4.3.2.実行可能なテストコード
// 0,
public class IncTest {
private volatile static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread a = new Thread() {
@Override
public void run() {
for( int j = 0 ; j < 1000000 ; j++ ) i++;
}
};
a.start();
Thread b = new Thread() {
@Override
public void run() {
for( int j = 0 ; j < 1000000 ; j++ ) i--;
}
};
b.start();
a.join();
b.join();
System.out.println(i);
}
}