記事のディレクトリ
1 CASは何ですか?
1.1ロック異なる原理をCASとアトミック性の問題を解決します
まず、次のコードを見て:
package com.nrsc.ch2.cas;
import java.util.ArrayList;
import java.util.List;
public class CasDemo {
//共享资源
static int i = 0;
public static void increase() {
i++;
}
public static void main(String[] args) throws InterruptedException {
Runnable r = () -> {
for (int j = 0; j < 1000; j++) {
increase();
}
};
List<Thread> threads = new ArrayList<>();
for (int j = 0; j < 10; j++) {
Thread thread = new Thread(r);
threads.add(thread);
thread.start();
}
//确保前面10个线程都走完
for (Thread thread : threads) {
thread.join();
}
System.out.println(i);
}
}
私は誰もが原因のコードを知っていると考えているi++不是原子操作
ので、10 *千万=より実行の10件のスレッドの最終的な結果につながります。
もちろん、私はほとんどの人が知っていることで信じている加锁可以解决这个问题
基本的な問題を解決するための原則をロックするには、次の図を使用してプロファイリングすることができます
が、実際にはCASのロック機構の使用に加えて、この問題を解決することができます。また、以来、それは別の解決策をロックされ、那它肯定是无锁的
そのための方法の問題点を解決するためにCASメカニズムの使用は、大きく以下の図でプロファイリングすることができます。
最後に、それはCAS何であると?それはどのようにこの問題を解決するために行うのですか?
1.2 CAS原理分析
(Baiduの百科事典から取られた)の定義を見てください:
比較およびスワップ、平行ケースの機構による性能損失をマルチスレッドロック溶液、CAS動作は3つのオペランド含む - メモリ位置(V)を、元の値(A)と新たな値(B)と期待されます。元の値のメモリ位置が期待値と一致する場合、プロセッサは、自動的に新しい値に位置値を更新します。そうでない場合、プロセッサは何もしません。いずれの場合も、CAS命令前の位置の値を返します。CASは、効果的に説明しました
“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。"
次に説明するための図を描きます:
2 CAS可能性のある問題
2.1 ABAの問題
実際に、私はABAの問題を考えるとき、CASは新しい真実を伝えるために。☺☺☺
1.2によって値をチェックし、動作時のCAS値を必要と、知っている可能性が更新されて変更されていない場合は、変更されていないが、その値がAであれば、Bになった、彼はAで、その後、CASを使用します> ABAの問題と呼ばれている - あなたは、その値が変更されていない見つけ、実際にチェックを変更します。
例えば、人気のポイントについて、あなたは他の何かをした、テーブルの上に水プットのガラスを注ぎ、その後、あなたは同僚はあなたが水のガラスを返した飲み、あなたはまだ水を見に戻ってきて、飲み物まで取得あなたは、人々が飲む水真ん中であれば、どんなには、水だけはまだ大丈夫、心配される;しかし、あなたがより衛生的に言えば人であれば、あなたは確かに動揺。。。
ソリューションABAの問題は、実際には非常に簡単であるバージョン番号を使用することです。次いで、追加の変数のバージョン番号、変数の更新バージョン番号は1だけインクリメントされるたびに、Aの前に→B→Aが1A→2B→3Aアップとなります。
2.2大きなオーバヘッド長いサイクル時間
時間が成功したスピンCASでない場合、それは非常に大きなCPUの実行コストをもたらすでしょう。
その唯一の共有変数を確実にするために2.3アトミック操作
共有変数の操作を行うとき、我々は、アトミック動作を保証するためにCASサイクルアプローチを使用することができるが、对多个共享变量操作时,循环CAS就无法保证操作的原子性,
この時間は、我々はできます用锁
。
トリッキーな方法もあり、動作するように共有変数に複数の共有変数をマージすることです。例えば、I 2、J = IJ = 2Aで、マージ=、およびCASのIJで動作する2つの共有変数があります。ジャワ1.5から出発し、JDKクラスAtomicReferenceは、オブジェクト間の参照原子はCAS動作における複数のオブジェクト内の変数が実行されることができることを確認するために提供しました。
CASのための3 JDKのサポート - 危険なクラス
Javaはsun.misc.unsafeクラスでは特に、次のように宣言し、CAS操作のサポートを提供します。
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
上記の意味のパラメータ:
- パラメータのvar1:操作するオブジェクトを表し
- パラメータVAR2:操作するオブジェクトのプロパティのオフセットアドレスを示しています
- パラメータVAR4:所望のデータニーズを表す値が変更されます
- パラメータVAR5 / var6:新しい鉱山を変更するには、の値を示し、
注意:
安全でないクラスがメモリ空間を操作するとCのポインタのようなJava言語を作る能力を持っている、それはまた、問題のポインタをもたらします。安全でないクラスの過度の使用は、エラーの可能性が大きくなるようになりますので、Javaの公式、ほとんどの公式ドキュメントの使用はお勧めしません。安全でないオブジェクトは、反射によって、直接呼び出すことはできません。
4つのJDKクラス関連アトミック操作はじめ - 根底CAS機構
4.1のAtomicInteger
- INT addAndGet(INTデルタ):数値例アトミック入力値(のAtomicInteger値内)を加え、その結果を返しています。
- ブールのcompareAndSet(INT、INTの更新を期待):入力値がアトミック入力値の値を設定した期待値に等しい場合。
- int型getAndIncrement():原子的に現在の値に1を加え、これはインクリメントする前に、戻り値であることに注意してください。
- int型getAndSet(int型newValueに):アトミックnewValueにの値に設定し、古い値を返します。
4.2 AtomicIntegerArray
主な方法は、以下のように使用されるアトミック更新整数配列を、提供します。
- INT addAndGet(INT I、INTデルタ):私が追加されたインデックス位置の配列要素にアトミック入力値。
- ブールのcompareAndSet(INT iは、INTの更新を期待INT):現在の値が期待値に等しい場合、配列の要素がアトミックiは位置の値を更新するように設定されています。
AtomicIntegerArrayアレイ素子内部修飾が入ってくる配列に影響を及ぼさないようにするとき、メソッドに渡された値のアレイを構築することによって、その後AtomicIntegerArrayは、配列のコピーを提示する、ことに留意されたいです。
4.3アップデート参照型
あなたが複数のアトミック変数を更新する場合のAtomicIntegerのアトミック更新の基本的なタイプは、唯一、変数を更新することができ、あなたは、原子更新が提供されるこのクラスの参照型を使用する必要があります。アトミックパッケージには、次の3つのクラスを提供します。
- AtomicReference
アトミック更新参照型。 - AtomicStampedReference
利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在ABA问题了。这就是AtomicStampedReference的解决方案。AtomicMarkableReference跟AtomicStampedReference差不多, AtomicStampedReference是使用pair的int stamp作为计数器使用,AtomicMarkableReference的pair使用的是boolean mark。 还是那个水的例子,AtomicStampedReference可能关心的是动过几次,AtomicMarkableReference关心的是有没有被人动过,方法都比较简单。
- AtomicMarkableReference:
参照型のアトミック更新フラグセット。原子は、ブールフラグと参照タイプを更新することができます。コンストラクタはAtomicMarkableReference(V initialRef、booleaninitialMark)です。
4.4アトミック更新フィールドクラス
原子のクラスのフィールドを更新する必要がある場合、原子は、フィールドベースの更新を使用する必要があり、アトミックパッケージは、フィールド更新原子以下の3つのクラスが用意されています。
アトミックフィールドクラスを更新するには、2つの手順が必要です。アトミック更新フィールドクラスは抽象クラスであるため、最初のステップは、静的メソッドを使用して、それぞれの時間は、アップデータを作成するために)(必須newUpdaterを使用し、クラスを設定する必要があり、更新する属性。第二の工程、更新类的字段(属性)必须使用public volatile修饰符。
- AtomicIntegerFieldUpdater:
整数フィールドアップデータアトミック更新。 - AtomicLongFieldUpdater:
長い整数フィールドアップデータアトミック更新。 - AtomicReferenceFieldUpdater:
フィールドの原子更新参照型。