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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多线程与高并发(二):解析自旋锁CAS操作与volatile

發布時間:2024/2/28 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多线程与高并发(二):解析自旋锁CAS操作与volatile 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Volitile 作用:保證線程的可見性,同時禁止指令的重排序

多線程時,存在的問題在于,在一個線程中對副本的更改并沒有及時地反映到另外一個線程中。這就是線程之間的不可見。
對變量值加了 volitile 之后,一個線程中的改變,在另一個線程中可以立刻看到。

volatile 關鍵字,使一個變量在多個線程間可見,示例:

/*** volatile 關鍵字,使一個變量在多個線程間可見* A B線程都用到一個變量,java默認是A線程中保留一份copy,這樣如果B線程修改了該變量,則A線程未必知道* 使用volatile關鍵字,會讓所有線程都會讀到變量的修改值* * 在下面的代碼中,running是存在于堆內存的t對象中* 當線程t1開始運行的時候,會把running值從內存中讀到t1線程的工作區,在運行過程中直接使用這個copy,并不會每次都去* 讀取堆內存,這樣,當主線程修改running的值之后,t1線程感知不到,所以不會停止運行* * 使用volatile,將會強制所有線程都去堆內存中讀取running的值* * 可以閱讀這篇文章進行更深入的理解* http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html* * volatile并不能保證多個線程共同修改running變量時所帶來的不一致問題,也就是說volatile不能替代synchronized* @author mashibing*/ package com.mashibing.juc.c_012_Volatile;import java.util.concurrent.TimeUnit;public class T01_HelloVolatile {/*volatile*/ boolean running = true; //對比一下有無volatile的情況下,整個程序運行結果的區別void m() {System.out.println("m start");while(running) {}System.out.println("m end!");}public static void main(String[] args) {T01_HelloVolatile t = new T01_HelloVolatile();new Thread(t::m, "t1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} t.running = false;} }

餓漢單例模式

package com.mashibing.dp.singleton;/*** 餓漢式* 類加載到內存后,就實例化一個單例,JVM保證線程安全* 簡單實用,推薦使用!* 唯一缺點:不管用到與否,類裝載時就完成實例化* Class.forName("")* (話說你不用的,你裝載它干啥)*/ public class Mgr01 {private static final Mgr01 INSTANCE = new Mgr01();private Mgr01() {};public static Mgr01 getInstance() {return INSTANCE;}public void m() {System.out.println("m");}public static void main(String[] args) {Mgr01 m1 = Mgr01.getInstance();Mgr01 m2 = Mgr01.getInstance();System.out.println(m1 == m2);} }

懶漢單例模式

package com.mashibing.dp.singleton;/*** lazy loading* 也稱懶漢式* 雖然達到了按需初始化的目的,但卻帶來線程不安全的問題* 可以通過synchronized解決,但也帶來效率下降*/ public class Mgr06 {private static volatile Mgr06 INSTANCE; //JITprivate Mgr06() {}public static Mgr06 getInstance() {if (INSTANCE == null) {//雙重檢查synchronized (Mgr06.class) {if(INSTANCE == null) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}INSTANCE = new Mgr06();}}}return INSTANCE;}public void m() {System.out.println("m");}public static void main(String[] args) {for(int i=0; i<100; i++) {new Thread(()->{System.out.println(Mgr06.getInstance().hashCode());}).start();}} }

面試題:你聽說過單例模式嗎?單例模式里面有一種叫雙重檢查的你了解嗎?這個單例要不要加volitile?

CAS


AtomicInteger

/*** 解決同樣的問題的更高效的方法,使用AtomXXX類* AtomXXX類本身方法都是原子性的,但不能保證多個方法連續調用是原子性的* @author mashibing*/ package com.mashibing.juc.c_018_00_AtomicXXX;import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger;public class T01_AtomicInteger {/*volatile*/ //int count1 = 0;AtomicInteger count = new AtomicInteger(0); /*synchronized*/ void m() { for (int i = 0; i < 10000; i++)//if count1.get() < 1000count.incrementAndGet(); //count1++}public static void main(String[] args) {T01_AtomicInteger t = new T01_AtomicInteger();List<Thread> threads = new ArrayList<Thread>();for (int i = 0; i < 10; i++) {threads.add(new Thread(t::m, "thread-" + i));}threads.forEach((o) -> o.start());threads.forEach((o) -> {try {o.join();} catch (InterruptedException e) {e.printStackTrace();}});System.out.println(t.count);} }

如何解決ABA問題?

基礎數據類型即使出現了ABA,一般問題不大。
如果是一個Object,紅色對象指向黃色對象,黃色對象指向藍色對象。現在,紅色對象偷偷指向藍色對象,將藍色對象里的內容改變,再偷偷指回黃色對象,而黃色對象沒有察覺到紅色對象的ABA改變導致藍色對象的改變,這時候黃色對象后面的業務邏輯是不是還和原來保持一樣,這就不好說了~

解決方式:加版本號,后面檢查的時候連版本號一起檢查
Atomic里面有帶版本號的類AtomicStampedReference,目前還沒有人在面試的時候遇到過。

不需要加鎖是怎么做到的呢?原因是使用了Unsafe這個類,Unsafe類是個單例,這個類可以直接申請內存、釋放內存
JDK11做了一些大的改動,下圖是1.7版本時的Unsafe類。

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的多线程与高并发(二):解析自旋锁CAS操作与volatile的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。