CASと揮発性の理解を理解する

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によって変更された変数が書き込まれると、操作の実行順序を保証するためにメモリバリアが生成され、命令が再配置されません。

おすすめ

転載: blog.csdn.net/qq_41570752/article/details/108521900