logo

Javaアトミック

Javaでは、 アトミック変数 そして オペレーション 並行して使用されます。の マルチスレッド 環境が問題を引き起こす場合 同時実行性 統一されています。オブジェクトや変数などの共有エンティティは、プログラムの実行中に変更される場合があります。したがって、プログラムの不整合が生じる可能性があります。したがって、同時アクセス中に共有エンティティを管理することが重要です。このような場合、 アトミック変数 それに対する解決策になる可能性があります。このセクションでは、次のことについて説明します。 アトミック クラス、アトミック変数、アトミック操作 、例とともに。

Javaで配列を初期化する

このセクションに進む前に、次の点を必ず理解してください。 同期 、 そして ロック ジャワでは。

Java アトミック クラス

ジャワ を提供します java.util.concurrent.atomic アトミック クラスが定義されているパッケージ。アトミック クラスは、 ロックフリー そして スレッドセーフ 環境または単一変数でのプログラミング。アトミック操作もサポートしています。すべてのアトミック クラスには、volatile 変数を操作する get() メソッドと set() メソッドがあります。このメソッドは、揮発性変数の読み取りおよび書き込みと同じように機能します。

パッケージは次のアトミック クラスを提供します。

クラス 説明
アトミックブール値 ブール値をアトミックに更新するために使用されます。
アトミック整数 整数値をアトミックに更新するために使用されます。
AtomicIntegerArray 要素をアトミックに更新できる int 配列。
AtomicIntegerFieldUpdater 指定されたクラスの指定された volatile int フィールドへのアトミックな更新を可能にするリフレクション ベースのユーティリティ。
アトミックロング これは、long 値をアトミックに更新するために使用されます。
AtomicLongArray 要素がアトミックに更新される長い配列。
AtomicLongFieldUpdater 指定されたクラスの指定された揮発性の長いフィールドへのアトミック更新を可能にするリフレクション ベースのユーティリティ。
AtomicMarkableReference AtomicMarkableReference は、アトミックに更新できるマーク ビットとともにオブジェクト参照を維持します。
アトミックリファレンス アトミックに更新できるオブジェクト参照。
アトミックリファレンス配列 要素をアトミックに更新できるオブジェクト参照の配列。
AtomicReferenceFieldUpdater 指定されたクラスの指定された揮発性参照フィールドへのアトミック更新を可能にするリフレクション ベースのユーティリティ。
AtomicStampedReference AtomicStampedReference は、アトミックに更新できる整数の「スタンプ」とともにオブジェクト参照を維持します。
ダブルアキュムレーター 提供された関数を使用して更新された実行中の double 値を一緒に維持する 1 つ以上の変数。
二重加算器 最初にゼロの二重和を維持する 1 つ以上の変数。
ロングアキュムレータ 提供された関数を使用して更新された実行中の長い値を一緒に維持する 1 つ以上の変数。
長加算器 初期のゼロロングサムを一緒に維持する 1 つ以上の変数。

これらのクラスのオブジェクトは、次のアトミック変数を表します。 int、long、ブール値 、およびオブジェクト 参照 それぞれ。アトミック クラスには、次のようないくつかの共通メソッドがあります。

メソッド 説明
セット() 値を設定するために使用されます。
得る() 現在の値を取得するために使用されます。
レイジーセット() 最終的には指定された値に設定されます。
比較して設定 現在の値 == 期待値である場合、値を指定された更新された値にアトミックに設定します。

アトミックオペレーション

常に一緒に実行されるこれらの操作は、 アトミック操作 または 原子アクション 。すべてのアトミック操作は、効率的に一度に実行されるか、まったく実行されないかのどちらかです。 三つ Java のアトミック アクションに関連する主要な概念は次のとおりです。

1. 原子性は、アクションとアクションのセットがどのようなものであるかを扱います。 見えない たとえば、次のコード スニペットを考えてみましょう。

 class NoAtomicOps { long counter=0; void increment() { for(;;) { count++; } } void decrement() { for(;;) { count--; } } //other statement } 

上記のコードでは、increment() と decrement() を同時に実行した場合の動作は次のようになります。 未定義 そして 予測できない

2. 可視性によって、1 つのスレッドの効果がいつ発揮されるかが決まります。 見た 別の人によって。たとえば、次のコード スニペットを考えてみましょう。

Java文字列のフォーマット
 class InfiniteLoop { boolean done= false; void work() { //thread T2 read while(!done) { //do work } } void stopWork() { //thread T1 write done=true; } //statements } 

上記のコードでは、スレッド T1 が Done を true に設定した後でも、スレッド T2 が停止しない可能性があります。また、スレッド間に同期がないわけではありません。

3. 順序によって、あるスレッド内のアクションが別のスレッドに対して順序どおりに実行されない場合が決まります。

 class Order { boolean a=false; boolean b=false; void demo1() //thread T1 { a=true; b=true; } boolean demo2() //thread T2 { boolean r1=b; //sees true boolean r2=a; //sees false boolean r3=a; //sees true //returns true return (r1 && !r2) && r3; } } 

スレッド T2 でのフィールド a と b の出現順序は、スレッド T1 で設定された順序と異なる場合があります。

例を通してそれを理解しましょう。

 public class AtomicExample { int count; public void incrementCount() { count=1; } 

上記のコード スニペットでは、int 型の変数を宣言しています。 カウント このような場合、すべてが同時に起こるか、まったく起こらないかのどちらかです。したがって、それは、 アトミック操作 そしてその操作は次のように知られています 原子性

コマンド arp-a

別のコード スニペットを考えてみましょう。

 public class AtomicExample { int count; public void incrementCount() { count=count+1; } 

これもアトミック操作であるように見えますが、そうではありません。これは、読み取り、変更、書き込みという 3 つの操作で構成される線形操作です。したがって、部分的に実行することができます。しかし、上記のコードをマルチスレッド環境で使用すると、問題が発生します。

シングルスレッド環境で上記のコードを呼び出したと仮定すると、更新された count の値は 2 になります。上記のメソッドを 2 つの別個のスレッドで呼び出した場合、両方のスレッドが同時に変数にアクセスし、 の値も更新します。同時に数えます。この状況を回避するために、アトミック操作を使用します。

Java は、次のようないくつかのタイプのアトミック アクションをサポートしています。

  • 揮発性 変数
  • 低レベルのアトミック操作 (安全ではありません)
  • アトミッククラス

アトミック操作を作成する方法を見てみましょう。

アトミック変数

アトミック変数を使用すると、変数に対してアトミック操作を実行できます。アトミック変数は同期を最小限に抑え、メモリ整合性エラーの回避に役立ちます。したがって、同期が保証されます。

アトミック パッケージは、次の 5 つのアトミック変数を提供します。

Java列挙型
  • アトミック整数
  • アトミックロング
  • アトミックブール値
  • AtomicIntegerArray
  • AtomicLongArray

アトミック変数の必要性

次のコードを考えてみましょう。

Counter.java

 class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <p>The above program gives the expected output if it is executed in a single-threaded environment. A multi-threaded environment may lead to unexpected output. The reason behind it that when two or more threads try to update the value at the same time then it may not update properly.</p> <p>Java offers <strong>two</strong> solutions to overcome this problem:</p> <ul> <li>By using lock and synchronization</li> <li>By using atomic variable</li> </ul> <p>Let&apos;s create a Java program and use an atomic variable to overcome the problem.</p> <h3>By using Atomic Variable</h3> <p> <strong>AtomicExample.java</strong> </p> <pre> class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;></pre></max;>

上記のプログラムは、シングルスレッド環境で実行すると、期待どおりの出力を返します。マルチスレッド環境では、予期しない出力が発生する可能性があります。その背後にある理由は、2 つ以上のスレッドが同時に値を更新しようとすると、正しく更新されない可能性があるためです。

Java のオファー この問題を克服するための解決策:

  • ロックと同期を使用する
  • アトミック変数を使用する

Java プログラムを作成し、アトミック変数を使用して問題を解決しましょう。

アトミック変数を使用する

AtomicExample.java

 class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, \'first\'); t2="new" \'second\'); t3="new" \'third\'); t4="new" \'fourth\'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;>

同期 vs.アトミック vs.揮発性

同期済み アトミック 揮発性
これはメソッドにのみ適用されます。 変数にのみ適用されます。 これは変数のみにも適用されます。
これにより、原子性とともに可視性が確保されます。 また、原子性とともに可視性も確保されます。 これはアトミック性ではなく可視性を保証します。
同じことを達成することはできません。 同じことを達成することはできません。 RAM に保存されるため、揮発性変数へのアクセスが高速になります。ただし、スレッドセーフと同期は提供されません。
同期ブロックまたは同期メソッドとして実装できます。 同じことを達成することはできません。 同じことを達成することはできません。
同じクラス オブジェクトまたは異なるクラス オブジェクトをロックできます。 同じことを達成することはできません。 同じことを達成することはできません。