記事ディレクトリ
CASの理解
CASとは
CompareAndSweepは比較して交換します。
AtomicInteger atomicInteger = new AtomicInteger(1);
//期望值是1,如果达到,那么就更新为2,否则不更新
atomicInteger.compareAndSet(1,2);
スピンロック
現在のスレッドの作業メモリー内の値をメインメモリー内の値と比較します。値が予想される場合は、操作を実行します。それ以外の場合は、ループを続けます
。短所:
- サイクルには時間がかかります。
- 一度に1つの共有変数のみがアトミックであることが保証されます。
- ABA問題があります。
ABA問題
先にABA問題があるかもしれませんが、ABA問題とは何ですか?
簡単に言うと、スレッドAが特定の値を操作しているとき、スレッドBはメインメモリの値を特定の値に変更して復元します。スレッドAは、この値が誰かによって変更されたことを知りません。
の解き方?
アトミック参照
によると、データベースの楽観的ロックと同様に、バージョン番号を持つクラスです。
//这里设置值的时候传一个版本号
AtomicStampedReference<Integer> asr= new AtomicStampedReference<>(1,1);
//这里操作这个值的时候就将版本号加1,返回值为true则说明这个值未被别的线程修改过,false反之。
asr.compareAndSet(1,2, asr.getStamp(),asr.getStamp()+1);
揮発性
Volatileは、Java仮想マシンによって提供される軽量の同期メカニズム
です。1。可視性
を保証します。2。アトミック性を保証しません。3
。命令の再配置を禁止します。
視界体験
public class JMMDemo {
//保证可见性,如果不加,线程1会死循环
private volatile static int num = 0;
public static void main(String[] args) {
new Thread(()->{
//线程1
int count = 0;
while(num == 0){
}
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch(Exception e){
e.printStackTrace();
}
num = 1;
System.out.println(Thread.currentThread().getName()+num);
}
}
アトミックな経験は保証されません
//不保证原子性
public class VDemo02 {
private volatile static int num = 0;
public static void add(){
num++;//不是一个原子性操作
}
public static void main(String[] args) {
//理论num结果应该为2万
for (int i = 1; i <= 20; i++) {
new Thread(() ->{
for(int j = 0; j < 1000; j++){
add();
}
},String.valueOf(i)).start();
}
while(Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + " " + num);
}
}
- 上記の操作、num ++はアトミック操作ではなく、複数のスレッドがこのように一緒に動作するため、numの値は20000の期待値ではなくなります。
- この問題を解決するには、アトミッククラス、つまり上記で使用したAtomicIntegerを使用してnumを変更します。
命令の再配置を無効にする
私たちが書いたプログラム、コンピューターは私たちが書いたときに実行されません。
ソースコード->コンパイラ最適化再配置->命令並列処理も再配置可能->メモリシステムも再配置->実行
プロセッサはデータ間の依存関係を考慮して命令再配置を実行します。
Volatileによって変更された変数が書き込まれると、操作の実行順序を保証するためにメモリバリアが生成され、命令が再配置されません。