日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java多线程之CAS缺点

發(fā)布時間:2024/2/28 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程之CAS缺点 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java多線程之CAS缺點


目錄:

  • 循環(huán)時間開銷很大
  • 只能保證一個共享變量的原子操作
  • 引來ABA問題及解決方案(重點)

  • 1. 循環(huán)時間開銷很大


    通過看源碼,我們發(fā)現(xiàn)有個do while,如果CAS失敗,會一直進(jìn)行嘗試。如果CAS長時間一直不成功,可能會給CPU帶來很大的開銷。


    2. 只能保證一個共享變量的原子操作

    當(dāng)對一個共享變量執(zhí)行操作時,我們可以使用循環(huán)CAS的方式來保證原子操作。但是,對多個共享變量操作時,循環(huán)CAS就無法保證操作的原子性,這個時候就可用鎖來保證原子性。


    3. 引來ABA問題及解決方案(重點)


    1.ABA問題概述

  • CAS會導(dǎo)致"ABA問題”
  • CAS算法實現(xiàn)一個重要前提需要取出內(nèi)存中某時刻的數(shù)據(jù)并在當(dāng)下時刻比較并替換,那么在這個時間差類會導(dǎo)致數(shù)據(jù)的變化。
  • 比如說一個線程one從內(nèi)存位置V中取出A,這時候另一個線程two也從內(nèi)存中取出A,并且線程two進(jìn)行了一些操作將值變成了B,然后線程two又將V位置的數(shù)據(jù)變成A,這時候線程One進(jìn)行CAS作發(fā)現(xiàn)內(nèi)存中仍然是A,然后線程One操作成功。
  • 盡管線程One的CAS慢作成功,但是不代表這個過程就是沒有問題的。
  • 2. 原子引用

    解決ABA問題只靠CAS不能解決,還需要用到原子引用技術(shù)。即AtomicReference

    簡單代碼測試

    import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString;import java.util.concurrent.atomic.AtomicReference;@Getter @ToString @AllArgsConstructor class User{String userName;int age; } public class AtomicReferenceDemo {public static void main(String[] args) {User z3 = new User("Z3",22);User li4 = new User("li4",25);AtomicReference<User> atomicReference = new AtomicReference<>();atomicReference.set(z3);System.out.println(atomicReference.compareAndSet(z3, li4)+"\t"+atomicReference.get().toString());System.out.println(atomicReference.compareAndSet(z3, li4)+"\t"+atomicReference.get().toString());} }

    編譯結(jié)果

    3. ABA問題解決方案

    解決: 原子引用+修改版本號(類似時間戳)

    代碼:

    import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicStampedReference;/*** ABA問題的解決: AtomicStampedReference*/ public class ABADemo {static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);public static void main(String[] args) {System.out.println("=============以下是ABA問題的產(chǎn)生==============");new Thread(() -> {atomicReference.compareAndSet(100, 101);atomicReference.compareAndSet(101, 100);}, "t1").start();new Thread(() -> {try {//暫停一秒鐘,保證上面的t1完成了一次ABA操作TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicReference.compareAndSet(100, 2019)+ "\t" + atomicReference.get());}, "t2").start();//暫停兩秒鐘等上面代碼執(zhí)行完try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("=============以下是ABA問題的解決==============");new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + "\t第一次版本號" + stamp);// 暫停一秒鐘t3線程,為了t4線程也能拿到相同的stamp。try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicStampedReference.compareAndSet(100, 101,atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName() + "\t第2次版本號" + atomicStampedReference.getStamp());atomicStampedReference.compareAndSet(101, 100,atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName() + "\t第2次版本號" + atomicStampedReference.getStamp());}, "t3").start();new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + "\t第一次版本號" + stamp);// 暫停3秒鐘t4線程,保證上面的t3線程完成了一次ABA操作。try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}boolean result = atomicStampedReference.compareAndSet(100, 101, stamp, stamp + 1);System.out.println(Thread.currentThread().getName() + "\t修改成功否:" + result+ "\t當(dāng)前最新實際版本號:" + atomicStampedReference.getStamp());System.out.println(Thread.currentThread().getName() + "\t當(dāng)前實際最新值" + atomicStampedReference.getReference());}, "t4").start();} }

    編譯結(jié)果:

    總結(jié)

    以上是生活随笔為你收集整理的Java多线程之CAS缺点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。