Java 仕様では、プリミティブ変数の割り当てが常にアトミックであることを保証しています ( forlong
と double types
.
それどころか、有名なインクリメント操作に対応するFetch-and-Addi++
操作は、読み取り-変更-書き込み操作につながるため、非アトミックになります。
このコードを仮定します:
public void assign(int b) {
int a = b;
}
生成されたバイトコードは次のとおりです。
public void assign(int);
Code:
0: iload_1
1: istore_2
2: return
したがって、割り当ては2 つのステップ (読み込みと保存) で構成されていることがわかります。
このコードを仮定します:
public void assign(int b) {
int i = b++;
}
バイトコード:
public void assign(int);
Code:
0: iload_1
1: iinc 1, 1 //extra step here regarding the previous sample
4: istore_2
5: return
X86 プロセッサが (少なくとも最新のプロセッサで) できることを知っていると、次のようにインクリメント操作をアトミックに操作できます。
コンピューター サイエンスでは、フェッチ アンド アド CPU 命令は、メモリ位置の内容をアトミックに変更する特別な命令です。これは、セマフォの一般化である、マルチプロセッサ システムでの相互排除および同時実行アルゴリズムの実装に使用されます。
したがって、最初の質問:バイトコードには両方のステップ (ロードとストレージ) が必要であるという事実にもかかわらず、Java は、代入操作がプロセッサのアーキテクチャに関係なく常にアトミックに実行される操作であり、永続的なアトミック性 (プリミティブ代入の場合) を保証できるという事実に依存していますか? ) その仕様で?
2 番目の質問:i++
非常に最新の X86 プロセッサを使用し、コンパイルされたコードを異なるアーキテクチャ間で共有することなく、操作 (または)を同期する必要がまったくないことを確認するのは間違っていAtomicInteger
ますか? それを考えると、すでにアトミックです。