この記事を読む前に、最初に「 Java Multithreaded Atomic Packageの紹介と使用」を読んで、Atomic Packageの関連するコンテンツについて学ぶことができます。
1。アトミックとは何ですか?
アトミックという言葉は、かつて最小の物質の単位と見なされていた原子と関係があります。コンピューター内のアトミックは、それがいくつかの部分に分割できないことを意味します。コードがアトミックと見なされる場合、実行中にコードを中断できないことを意味します。一般的に言えば、アトミック命令はハードウェアによって提供され、ソフトウェアによってアトミックメソッドを実装するために提供されます(実行が完了するまでメソッドを入力した後、スレッドは中断されません)
X86プラットフォームでは、CPUは、命令実行中にバスをロックする手段を提供します。 CPUチップにはリード#hlockpinがあります。接頭辞「ロック」がアセンブリ言語プログラムの命令に追加された場合、アセンブリマシンコードにより、この命令を実行するときにCPUが#hlockpinの可能性を低下させ、この命令の終了までリリースし、バスをロックします。このようにして、同じバスに乗っている他のCPUは、当面バスからメモリにアクセスできず、マルチプロセッサ環境でのこの命令の原子性を確保します。
2。java.util.concurrentの原子変数
直接的であろうと間接であろうと、java.util.concurrentパッケージのほとんどすべてのクラスは、同期ではなく原子変数を使用します。 concurrentlinkedqueueのようなクラスは、アトミック変数を使用して待機中のアルゴリズムを直接実装しますが、concurrenthashmapのようなクラスはreentrantlockを使用して必要に応じてロックします。その後、ReentrantLockは原子変数を使用して、ロックを待っているスレッドキューを維持します。
JDK5.0のJVMの改善がなければ、これらのクラスは構築されず、ハードウェアレベルの同期プリミティブにアクセスするための(ユーザークラスではなく、クラスライブラリに)露出します。 java.util.concurrentの原子変数クラスおよびその他のクラスは、これらの機能をユーザークラスに公開します
java.util.concurrent.atomicの原子クラス
このパッケージは、一連の原子クラスを提供します。その基本的な特徴は、マルチスレッド環境では、複数のスレッドがこれらのクラスのインスタンスに含まれるメソッドを同時に実行すると、排他的であり、つまり、スレッドがメソッドに入り、その中で命令を実行する場合、他のスレッドによって中断されず、他のスレッドはスピンロックのようなものです。メソッドが実行されるまで、JVMは待機キューから別のスレッドを選択して入力します。これは単なる論理的理解です。実際、関連するハードウェア命令の助けを借りて実装されており、スレッドをブロックしません(または、ハードウェアレベルでブロックされているだけです)。クラスは4つのグループに分けることができます
Atomicboolean、Atomicinteger、Atomiclong、AtomicReference
AtomicintegerArray、Atomiclongarray
Atomiclongfieldupdater、Atomicintegerfieldupdater、AtomicReferenceFieldUpdater
AtomicMarkableReference、AtomicStampedReference、AtomicReferencearray
その中で、Atomicboolean、Atomicinteger、Atomiclong、AtomicReferenceは似ています。
まず第一に、Atomicboolean、Atomicinteger、Atomiclong、AtomicReference内部APIは似ています。
AtomicReferenceを備えたスレッドセーフスタックを作成します
public class linkedStack <t> {private atomicReference <node <node <t >> stacks = new AtomicReference <node <t >>(); public t push(t e){node <t> oldnode、newNode; (true){//ここでの処理は非常に特別であり、そうでなければなりません。 oldnode = stacks.get(); newNode = new node <t>(e、oldnode); if(stacks.compareandset(oldnode、newnode)){return e;}}} public t pop(){node <t> oldnode、newNode; (stacks.compareandset(oldnode、newnode)){return oldnode.object;}}}} private static final class node <t> {private t object; private node <t> next; private node(t object、node <t> next){this.object = object; this.next =;}}}}}}}次に、フィールドのアトミックアップデートに焦点を当てます。
Atomicintegerfieldupdater <T>/AtomicLongFieldUpDater <T>/AtomicReferenceFieldUpDater <T、V>は、反射に基づくフィールドの値です。
対応するAPIも非常に単純ですが、いくつかの制約もあります。
(1)フィールドは揮発性の種類でなければなりません!揮発性とは何ですか? 「 Javaの揮発性キーワードの詳細な説明」を確認してください
(2)フィールドの説明タイプ(修飾子public/protected/default/private)は、発信者と操作オブジェクトフィールドの関係と一致しています。つまり、発信者はオブジェクトフィールドを直接操作してから、原子操作を反映して実行できます。ただし、親クラスのフィールドの場合、サブクラスは直接操作できませんが、サブクラスは親クラスのフィールドにアクセスできます。
(3)インスタンス変数のみであり、クラス変数ではなく、静的キーワードを追加することはできません。
(4)変数のみを変更でき、最終変数のセマンティクスが変更されていないため、最終変数にすることはできません。実際、最終的で不安定な紛争のセマンティクス、およびこれら2つのキーワードは同時に存在することはできません。
(5)AtomicintegerfieldupdaterおよびAtomiclongfieldupdaterの場合、int/longタイプのフィールドのみを変更することができ、ラッパータイプ(整数/長い)を変更することはできません。ラッピングタイプを変更する場合は、AtomicReferenceFieldUpDaterを使用する必要があります。
操作方法については、次の例で説明します。
java.util.concurrent.atomic.atomic.atomicintegerfieldupdater; public class atomicintegerfieldupdaterdemo {class demodata {public volatile int value1 = 1;揮発性int値2 = 2; {return Atomicintegerfieldupdater.newupdater(demodata.class、fieldname);} void doit(){demodata data = new.out.println( "1 ==>"+getUpdater( "value1")。 "+getUpDater(" value2 ")。incrementAndget(data)); system.out.println(" 2 ==> "+getUpdater(" value3 ")。decrentAndget(data)); system.out.println(" true ==> "+getUpdater(" value4 ")。 {atomicintegerfieldupdaterdemo demo = new Atomicintegerfieldupdaterdemo(); demo.doit();}}}上記の例では、Demodataのフィールド値3/value4はAtomicintegerfieldupdaterdemoクラスには見えないため、その値を反射によって直接変更することはできません。
AtomicMarkableReferenceクラスで説明されている<オブジェクト、boolean>のペアは、オブジェクトまたはブールの値を原子的に変更できます。このデータ構造は、一部のキャッシュまたは状態の説明でより有用です。この構造は、オブジェクト/ブールを個別にまたは同時に変更するときに、スループットを効果的に改善できます。
AtomicStampedReferenceクラスは、整数「フラグ」でオブジェクト参照を維持し、原子的に更新できます。 AtomicmarkAblereferenceクラスの<オブジェクト、ブールン>と比較して、AtomicStampedReferenceは、実際にはオブジェクトの同時カウントである<Object、int>に類似したデータ構造を維持します(参照)。ただし、AtomicIntegerとは異なり、このデータ構造はオブジェクト参照を運ぶことができ、このオブジェクトでアトミック操作を実行して同時にカウントできます。
この記事の最後に「ABAの問題」が言及され、Atomic MarkedAblereference/AtomicStampedReferenceは「ABA問題」を解決するのに役立ちます。
iii。原子の役割
これにより、単一のデータの動作を霧化できます
アトミッククラスを使用して、複雑なブロッキングフリーコードを構築します
2つ以上の原子変数(または単一の原子変数で2つ以上の操作を実行する)にアクセスすることは、一般に、これらの操作を原子単位として使用できるように同期を必要とすると見なされます。
ロックも待機アルゴリズムもありません
CAS(CompareAndSwap)に基づく並行性アルゴリズムは、スレッドがロックするのをもう待つ必要がないため(スレッドプラットフォームの用語に応じて、ミューテックスまたは重要な部分と呼ばれることもある)ため、ロックフリーアルゴリズムと呼ばれます。 CASの動作が成功するか失敗するかどうか、どちらの場合も、予測可能な時間内に完了します。 CASが失敗した場合、発信者はCAS操作を再試行したり、他の適切な操作を実行したりできます。
他のスレッドが遅延(または失敗した)ときに各スレッドが動作し続ける場合、アルゴリズムが待機していないと言えます。対照的に、ロックフリーアルゴリズムでは、特定のスレッドのみが常に操作を実行する必要があります。 (待機のもう1つの定義は、他のスレッドの操作、タイミング、クロスオーバー、または速度に関係なく、各スレッドが限られたステップで独自の操作を正しく計算することを保証することです。この制限は、システム内の10個のスレッドの数の関数になります。たとえば、各スレッドがCascounter.increment.increment()操作を実行する前に、cascounter.increment()操作を完了します。
過去15年にわたって、人々は待機中およびロックフリーのアルゴリズム(非ブロッキングアルゴリズムとも呼ばれる)に関する広範な研究を実施しており、多くの人々が一般的なデータ構造で非ブロッキングアルゴリズムを発見しました。非ブロッキングアルゴリズムは、オペレーティングシステムとJVMレベルで広く使用されており、スレッドやプロセススケジューリングなどのタスクを実行します。それらの実装はより複雑ですが、ロックベースの代替アルゴリズムよりも多くの利点があります。優先度の反転やデッドロックなどの危険を避けることができます。
一般:
非ブロッキングカウンター
非ブロッキングスタックConcurrentStack
非ブロッキングリンクリストConcurrentLinkedQueue
ABAの質問:
Vを変更する前に、CASは主に「Vの値がまだA」であるかどうかを尋ね、Vを初めて読み取り、VでCAS操作を実行し、AからBに戻し、次にAに戻るCASベースのアルゴリズムを混同します。この場合、CASの動作は成功しますが、場合によっては、結果が期待したものではない場合があります。このタイプの問題は、ABA問題と呼ばれます。これは、通常、タグまたはバージョン番号を各値に関連付けて、CAS操作で実行される値とタグを原子的に更新することによって処理されます。 AtomicStampedReferenceクラスはこの方法をサポートしています。
要約します
上記は、Java Multi-Threaded Atomicパッケージの原子変数と原子クラスの動作に関するこの記事のすべての詳細な説明です。私はそれが誰にでも役立つことを願っています。興味のある友達は引き続きこのサイトを参照できます:
Javaプログラミング:マルチスレッドデッドロックとスレッド間の通信は簡単なコードです
Javaマルチスレッドプログラミング小さな例は、駐車場システムをシミュレートします
Javaマルチスレッドの利点とコード例に関する簡単な議論
欠点がある場合は、それを指摘するためにメッセージを残してください。