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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

synchronized,ReetrantLock与volatile(二)

發布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 synchronized,ReetrantLock与volatile(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

volatile?

? ? ?Volatile 變量具有?synchronized?的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現 volatile 變量的最新值。在理解volatile作用時候,我們先看看jvm的內存模型。

? ??

? ? ?Java內存模型規定,對于多個線程共享的變量,存儲在主內存當中,每個線程都有自己獨立的工作內存,線程只能訪問自己的工作內存,不可以訪問其它線程的工作內存。工作內存中保存了主內存共享變量的副本,線程要操作這些共享變量,只能通過操作工作內存中的副本來實現,操作完畢之后再同步回到主內存當中。

? ? 一個變量被定義為volatile,那說明這個變量是易變的。如果一個線程修改了這個變量,那這個線程將通知其他線程這個變量已做修改,工作內存保持的變量副本時效,必須重新從共享內存讀取這個變量的最新值,因此,被volatile非常適合做狀態標識。

public?class?Volatile?{private?volatile?static?boolean?flag?=?true;public?static?void?work()?{while?(flag)?{System.out.println("=============");}}public?static?void?stop()?{flag?=?false;System.out.println("----stop?work----");}public?static?void?main(String[]?args)?{new?Thread(new?Runnable()?{public?void?run()?{work();}}).start();new?Thread(new?Runnable()?{public?void?run()?{try?{Thread.sleep(100l);}?catch?(InterruptedException?e)?{}stop();}}).start();} }

? ? ? 可以看見線程馬上結束了自己的工作,但是我們如果不用volatile修飾flag,還是發現線程也馬上停止了在控制臺的打印。HotSpot編譯器在server模式和client模式編譯不同, 在client模式下,多線程讀取變量時,都會直接從主內存中去讀取,不會保存在工作內存中,所有加不加volatile效果一樣,而server模式下,則對代碼做了優化。而eclipse中默認的啟動模式client。


ReetrantLock

? ? ?(畫了一張不知道是什么圖的圖),圖上我們可以看出,ReetrantLock有有屬性Sync sync,FairSync和NonFairSync是Sync的兩個子類,Sync繼承自AQS(AbstractQueuedSynchronizer)。

? ?

? ??很明顯,ReetrantLock實現了公平鎖和非公平鎖。通過源碼我們可以看出ReetrantLock默認為非公平鎖,并且提供了一個boolean參數的構造函數,true為公平鎖,false為非公平鎖。

?public?ReentrantLock(){sync?=?new?NonfairSync();}public?ReentrantLock(boolean?flag){sync?=?((Sync)?(flag???((Sync)?(new?FairSync()))?:?((Sync)?(new?NonfairSync()))));}

? ?現在我們來看看你ReetrantLock.lock()到底干了什么?

?//FairSync:final?void?lock(){acquire(1);}//NonFairSync:final?void?lock(){if(compareAndSetState(0,?1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}//acquire(int?i):public?final?void?acquire(int?i){if(!tryAcquire(i)?&&?acquireQueued(addWaiter(Node.EXCLUSIVE),?i))selfInterrupt();}

? ? 非公平鎖一開始嘗試檢查state的值,如果是0就通過CAS看是否能成功置成1,操作如果成功,那么該線程獲得鎖,而公平鎖并沒有,這也就是公平和非公平的區別。如果非公平鎖對state的CAS沒有成功,則和公平鎖一樣acquire()。

?//FairSync:protected?final?boolean?tryAcquire(int?i){Thread?thread?=?Thread.currentThread();int?j?=?getState();if(j?==?0){if(!hasQueuedPredecessors()?&&?compareAndSetState(0,?i)){setExclusiveOwnerThread(thread);return?true;}}?elseif(thread?==?getExclusiveOwnerThread()){int?k?=?j?+?i;if(k?<?0){throw?new?Error("Maximum?lock?count?exceeded");}?else{setState(k);return?true;}}return?false;}//NonFairSync:final?boolean?nonfairTryAcquire(int?i){Thread?thread?=?Thread.currentThread();int?j?=?getState();if(j?==?0){if(compareAndSetState(0,?i)){setExclusiveOwnerThread(thread);return?true;}}?elseif(thread?==?getExclusiveOwnerThread()){int?k?=?j?+?i;if(k?<?0){throw?new?Error("Maximum?lock?count?exceeded");}?else{setState(k);return?true;}}return?false;}

? ? ?同樣在tryAcquire中,公平鎖在state=0的情況下看了看sync隊列中有沒有人排在前面(確實是挺公平的),而非公平鎖完全是不管這條件的,我們再來看看acquireQueued(addWaiter(Node.EXCLUSIVE), i),addWaiter是把線程包裝成Node,這里就不貼出來了。

final?boolean?acquireQueued(final?Node?node,?int?arg)?{boolean?failed?=?true;try?{boolean?interrupted?=?false;for?(;;)?{final?Node?p?=?node.predecessor();//如果當前的節點是head說明他是隊列中第一個“有效的”節點,因此嘗試獲取if?(p?==?head?&&tryAcquire(arg))?{setHead(node);p.next?=?null;failed?=?false;return?interrupted;}//否則,檢查前一個節點的狀態為,看當前獲取鎖失敗的線程是否需要掛起。//如果需要,借助JUC包下的LockSopport類的靜態方法Park掛起當前線程。if?(shouldParkAfterFailedAcquire(p,?node)&&parkAndCheckInterrupt())?interrupted?=?true;}}?finally?{//如果有異常if?(failed)//?取消請求,對應到隊列操作,就是將當前節點從隊列中移除。?cancelAcquire(node);} }

? ? ? ?到此為止,一個線程對于鎖的一次競爭才告一段落,結果又兩種,要么成功獲取到鎖(不用進入到AQS隊列中),要么獲取失敗被掛起,等待下次喚醒后繼續循環嘗試獲取鎖,值得注意的是,AQS的隊列為FIFO隊列,所以,每次及時被CPU假喚醒,且當前線程不是出在頭節點的位置,也是會被掛起的。(為了防止篇幅過長,AQS中的condition和node將在下篇講)。


? ? ? ?那么問題來了,sychronized和ReentranLock各自要在什么場合用呢?下面貼一下各大博客的總結吧

? ? ? ?synchronized是托管給JVM執行的,而lock是java寫的控制鎖的代碼。在Java1.5中,synchronize是性能低效的。因為這是一個重量級操作,需要調用操作接口,導致有可能加鎖消耗的系統時間比加鎖以外的操作還多。相比之下使用Java提供的Lock對象,性能更高一些。但是到了Java1.6,發生了變化。synchronize在語義上很清晰,可以進行很多優化,有適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他們也更支持synchronize,在未來的版本中還有優化余地。

? ? ? ?synchronized原語和ReentrantLock在一般情況下沒有什么區別,但是在非常復雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。
? ? ?1.某個線程在等待一個鎖的控制權時需要中斷
? ? ?2.多個條件變量或者鎖投票
? ? ?3.時間鎖等候或者無塊機構鎖

轉載于:https://my.oschina.net/chener/blog/478640

總結

以上是生活随笔為你收集整理的synchronized,ReetrantLock与volatile(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

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