ホームページ >Java >&#&チュートリアル >マルチスレッド環境での Java 命令の並べ替えを解決する方法
命令の再配置は、シングルスレッド環境ではプログラムの実行効率の向上に役立ち、プログラムに悪影響を及ぼしませんが、マルチスレッド環境では、命令の再配置は、プログラムに驚きをもたらす、予期しないエラー。
以下は命令の並び替えを完全に回復できる例です。
public class D { static Integer a; static Boolean flag; public static void writer() { a = 1; flag = true; } public static void reader() { if (flag != null && flag) { System.out.println(a); a = 0; flag = false; } } }
reader
メソッドは、flag
変数が true の場合にのみ、変数 a
をコンソールに出力します。価値。
writer
メソッドは、まず変数 a
の代入演算を実行し、次に変数 flag
の代入演算を実行します。
上記の分析ロジックに従う場合、コンソールに出力される結果はすべて 1 である必要があります。
コードに命令の再配置がない場合、flag
変数が true の場合、変数 a
は 1 でなければなりません。 。
上記のコードでは、変数 a
と変数 flag
に関する両方のメソッド クラスで命令の再配置があります。
public static void writer() { a = 1; flag = true; }
ログ出力を観察すると、多数の 0 出力があることがわかりました。
writer
メソッド内で命令の再配置が発生すると、flag
変数が最初に割り当てを完了します。このとき、現在のスレッドが中断されると、他のスレッドも中断されます。 reader
メソッドを呼び出し、flag
変数が true であることを検出し、変数 a
の値を出力します。この時点で、コンソールには期待値を超える結果が表示されます。
new キーワードを使用してオブジェクトを作成する場合、非アトミックな操作であるため、命令の再配置が発生します。マルチスレッド環境への影響。
public class Singleton { private static UserModel instance; public static UserModel getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new UserModel(2, "B"); } } } return instance; } } @Data @AllArgsConstructor class UserModel { private Integer userId; private String userName; }
キーワード new を使ってオブジェクトを作成するのですが、大まかに次のようなプロセスに分かれます。
## スタック スペースに参照アドレスを作成します。#クラス ファイルをテンプレートとして使用して、ヒープ スペース オブジェクトにメモリを割り当てます。
#2. 並べ替えプロセスの分析
後続のスレッドで
instance(1) AtomicReference アトミック クラス
アトミック クラスを使用して、その特性を利用して関連する変数のセットをオブジェクトにカプセル化します。アトミックな操作を実現し、コマンドの再配置の問題を効果的に回避します。 <pre class="brush:java;">@Data
@NoArgsConstructor
@AllArgsConstructor
public class ValueModel {
private Integer value;
private Boolean flag;
}</pre>
アトミック クラスは、マルチスレッド環境で命令を並べ替える場合に推奨されるソリューションです。理解しやすいだけでなく、スレッド間で使用される非ヘビーウェイト ミューテックスは比較的効率的です。
public class E { private static final AtomicReference<ValueModel> ar = new AtomicReference<>(new ValueModel()); public static void writer() { ar.set(new ValueModel(1, true)); } public static void reader() { ValueModel valueModel = ar.get(); if (valueModel.getFlag() != null && valueModel.getFlag()) { System.out.println(valueModel.getValue()); ar.set(new ValueModel(0, false)); } } }関連する変数のグループが命令の再配置を受ける場合、アトミック操作クラスを使用する方が良い解決策です。
(2) volatile キーワード
public class Singleton { private volatile static UserModel instance; public static UserModel getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new UserModel(2, "B"); } } } return instance; } } @Data @AllArgsConstructor class UserModel { private Integer userId; private String userName; }
4. 命令の再配置についての理解
1. 命令の再配置が広く普及している命令の再配置 配置は整っていないJava プログラムに限定されますが、実際には、ソフトウェアから CPU ハードウェアに至るまで、さまざまなコンパイラで命令の再配置操作が行われます。命令の再配置は、シングル スレッド プログラムのパフォーマンスの最適化です。命令の再配置によって、シングル スレッド環境での順次プログラムの実行で期待される結果が変わるわけではないことは明らかです。
関連する変数の場合は、まずそれらをオブジェクトにカプセル化してから、アトミック クラスを使用して操作します。
新しいオブジェクトの場合は、volatile キーワードを使用しますオブジェクトは、ターゲットを変更できます。
3. 同期ロックは、並べ替えとは何の関係もありません。
同期ロックを使用すると、マルチスレッド環境での並べ替えによる悪影響を回避できますが、ミューテックス ロックによって生じるスレッドのオーバーヘッドが比較的大きいため、お勧めできません。
以上がマルチスレッド環境での Java 命令の並べ替えを解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。