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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java Review - 并发编程_锁的分类

發布時間:2025/3/21 java 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Review - 并发编程_锁的分类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 樂觀鎖與悲觀鎖
  • 公平鎖與非公平鎖
  • 獨占鎖與共享鎖
  • 可重入鎖
  • 自旋鎖


樂觀鎖與悲觀鎖

樂觀鎖和悲觀鎖是在數據庫中引入的名詞,但是在并發包鎖里面也引入了類似的思想。

悲觀鎖指對數據被外界修改持保守態度,認為數據很容易就會被其他線程修改,所以在數據被處理前先對數據進行加鎖,并在整個數據處理過程中,使數據處于鎖定狀態

悲觀鎖的實現往往依靠數據庫提供的鎖機制,即在數據庫中,在對數據記錄操作前給記錄加排它鎖。

  • 如果獲取鎖失敗,則說明數據正在被其他線程修改,當前線程則等待或者拋出異常。
  • 如果獲取鎖成功,則對記錄進行操作,然后提交事務后釋放排它鎖。

來看個例子

public int updateentry(long id) {//(1)使用悲觀鎖獲取指定記錄Entryobiect entry = query("select * from tablel where id=#(id) for update", id);//(2)修改記錄內容,根據計算修改 entry記錄的屬性String name=generatorname(entry);entry.setname(name);//(3) update操作int count= update("update tablel set name=#(name], age=#fage] where id =#{id}", entry);return count;}

假設updateEntry、query、update方法都使用了事務切面的方法,并且事務傳播性被設置為required

  • 執行updateEntry方法時如果上層調用方法里面沒有開啟事務,則會即時開啟一個事務,然后執行代碼(1)
  • 代碼(1)調用了query方法,其根據指定id從數據庫里面查詢出一個記錄。由于事務傳播性為requried,所以執行query時沒有開啟新的事務,而是加入了updateEntry開啟的事務,也就是在updateEntry方法執行完畢提交事務時,query方法才會被提交,就是說記錄的鎖定會持續到updateEntry執行結束
  • 代碼(2)則對獲取的記錄進行修改,代碼(3)把修改的內容寫回數據庫,同樣代碼(3)的update方法也沒有開啟新的事務,而是加入了updateEntry的事務。也就是updateEntry、query、update方法共用同一個事務
  • 多個線程同時調用updateEntry方法,并且傳遞的是同一個id時,只有一個線程執行代碼(1)會成功,其他線程則會被阻塞,這是因為在同一時間只有一個線程可以獲取對應記錄的鎖,在獲取鎖的線程釋放鎖前(updateEntry執行完畢,提交事務前),其他線程必須等待,也就是在同一時間只有一個線程可以對該記錄進行修改。

    樂觀鎖是相對悲觀鎖來說的,它認為數據在一般情況下不會造成沖突,所以在訪問記錄前不會加排它鎖,而是在進行數據提交更新時,才會正式對數據沖突與否進行檢測。具體來說,根據 update 返回的行數讓用戶決定如何去做。

    將上面的例子改為使用樂觀鎖的代碼如下。

    public boolean updateentry(long id){boolean result = false;int retrynum = 5;while(retrynum >0){//(1.1)使用樂觀鎖獲取指定記錄Entryobject entry =query("select *from tablel where id =#[id)",id);//(2.1)修改記錄內容, version字段不能被修改String name =generatorname(entry);entry. setname(name);//(3.1) update操作int count = update("update tablel set name=#(name), age=#(age), version=${version}+1 where id =#(id) and version=#(version)", entry);if (count == 1){result = true ;break;}retrynum--;}return result;}

    如上代碼使用retryNum設置更新失敗后的重試次數,如果代碼(3.1)執行后返回0,則說明代碼(1.1)獲取的記錄已經被修改了,則循環一次,重新通過代碼(1.1)獲取最新的數據,然后再次執行代碼(3.1)嘗試更新。這類似CAS的自旋操作,只是這里沒有使用死循環,而是指定了嘗試次數。

    樂觀鎖并不會使用數據庫提供的鎖機制,一般在表中添加 version 字段或者使用業務狀態來實現。樂觀鎖直到提交時才鎖定,所以不會產生任何死鎖


    公平鎖與非公平鎖

    根據線程獲取鎖的搶占機制,鎖可以分為公平鎖和非公平鎖

    • 公平鎖表示線程獲取鎖的順序是按照線程請求鎖的時間早晚來決定的,也就是最早請求鎖的線程將最早獲取到鎖。

    • 非公平鎖則在運行時闖入,也就是先來不一定先得。

    ReentrantLock 提供了公平和非公平鎖的實現。

    • 公平鎖:ReentrantLock pairLock = new ReentrantLock(true)。

    • 非公平鎖:ReentrantLock pairLock = new ReentrantLock(false)。如果構造函數不傳遞參數,則默認是非公平鎖

    假設線程 A 已經持有了鎖,這時候線程 B 請求該鎖其將會被掛起。當線程 A釋放鎖后,假如當前有線程 C 也需要獲取該鎖,如果采用非公平鎖方式,則根據線程調度策略,線程 B 和 線程C 兩者之一可能獲取鎖,這時候不需要任何其他干涉,而如果使用公平鎖則需要把 C 掛起,讓 B 獲取當前鎖。

    在沒有公平性需求的前提下盡量使用非公平鎖,因為公平鎖會帶來性能開銷。


    獨占鎖與共享鎖

    根據鎖只能被單個線程持有還是能被多個線程共同持有,鎖可以分為獨占鎖和共享鎖

    • 獨占鎖保證任何時候都只有一個線程能得到鎖

      獨占鎖是一種悲觀鎖,由于每次訪問資源都先加上互斥鎖,這限制了并發性,因為讀操作并不會影響數據的一致性,而獨占鎖只允許在同一時間由一個線程讀取數據,其他線程必須等待當前線程釋放鎖才能進行讀取。

    • 共享鎖則是一種樂觀鎖,它放寬了加鎖的條件,允許多個線程同時進行讀操作。

      ReentrantLock 就是以獨占方式實現的。

      共享鎖則可以同時由多個線程持有 ReadWriteLock 讀寫鎖,它允許一個資源可以被多線程同時進行讀操作。


    可重入鎖

    當一個線程要獲取一個被其他線程持有的獨占鎖時,該線程會被阻塞,那么當一個線程再次獲取它自己已經獲取的鎖時是否會被阻塞呢?如果不被阻塞,那么我們說該鎖是可重入的,也就是只要該線程獲取了該鎖,那么可以無限次數(嚴格來說是有限次數)地進入被該鎖鎖住的代碼。

    來個Demo, 看看在什么情況下會使用可重入鎖

    /*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/11/27 10:43* @mark: show me the code , change the world*/ public class KeCongRuLockDemo {// synchronized public synchronized void lockA(){System.out.println("lockA");}// synchronized public synchronized void lockB(){System.out.println("lockB , then call lockA");// 調用加鎖的A方法lockA();}public static void main(String[] args) {KeCongRuLockDemo lockDemo = new KeCongRuLockDemo();lockDemo.lockB();} }

    在如上代碼中,調用 lockB方法前會先獲取內置鎖,然后打印輸出。之后調用 lockA方法,在調用前會先去獲取內置鎖,如果內置鎖不是可重入的,那么調用線程將會一直被阻塞。

    實際上, synchronized 內部鎖是可重入鎖

    可重入鎖的原理是在鎖內部維護一個線程標示,用來標示該鎖目前被哪個線程占用,然后關聯一個計數器。一開始計數器值為0,說明該鎖沒有被任何線程占用。當一個線程獲取了該鎖時,計數器的值會變成1,這時其他線程再來獲取該鎖時會發現鎖的所有者不是自己而被阻塞掛起。

    但是當獲取了該鎖的線程再次獲取鎖時發現鎖擁有者是自己,就會把計數器值加+1,當釋放鎖后計數器值-1。當計數器值為0時,鎖里面的線程標示被重置為 null,這時候被阻塞的線程會被喚醒來競爭獲取該鎖

    可重入鎖兩個關鍵字: 線程標示 + 計數器


    自旋鎖

    由于Java中的線程是與操作系統中的線程一一對應的,所以當一個線程在獲取鎖(比如獨占鎖)失敗后,會被切換到內核狀態而被掛起

    當該線程獲取到鎖時又需要將其切換到內核狀態而喚醒該線程。而從用戶狀態切換到內核狀態的開銷是比較大的,在一定程度上會影響并發性能。

    自旋鎖是當前線程在獲取鎖時,如果發現鎖已經被其他線程占有,它不馬上阻塞自己,在不放棄CPU使用權的情況下,多次嘗試獲取(默認次數是10,可以使用-XX:PreBlockSpinsh參數設置該值),很有可能在后面幾次嘗試中其他線程已經釋放了鎖。如果嘗試指定的次數后仍沒有獲取到鎖則當前線程才會被阻塞掛起

    由此看來自旋鎖是使用CPU時間換取線程阻塞與調度的開銷,但是很有可能這些CPU時間白白浪費了.

    總結

    以上是生活随笔為你收集整理的Java Review - 并发编程_锁的分类的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 久艹在线播放 | 黑人精品无码一区二区三区 | 欧美成人aa | 久久精品天天中文字幕人妻 | 中国一级免费毛片 | 久久久网站 | 亚洲热av | 国产日韩在线免费观看 | 亚洲欧洲色图 | 久久3p | 日韩黄色免费 | 久草免费资源站 | 亚洲欧美激情在线 | 丰满熟妇被猛烈进入高清片 | 国产综合无码一区二区色蜜蜜 | 国产亚洲欧美在线 | 国产女主播福利 | 国产主播在线一区 | 天天看片中文字幕 | 久草手机在线观看 | 极品尤物魔鬼身材啪啪仙踪林 | 偷自在线 | 综合狠狠开心 | 日韩av综合网站 | 奇米网在线观看 | 自拍偷拍av | 波多野结衣黄色片 | 色国产在线| 亚洲欧美一区二区三区孕妇 | 国产精品乱码一区 | 男人激烈吮乳吃奶爽文 | 久久免费视频播放 | 欧美日韩在线视频一区 | 亚洲一区二区三区av无码 | 91亚洲精品一区二区乱码 | 天堂欧美城网站网址 | 欧美三级午夜理伦三级老人 | 中文字幕精品一区久久久久 | 成人激情综合 | 天天色成人网 | 日本免费a级片 | 国产精品高潮呻吟久久久 | 成人在线视频免费播放 | 日韩精品一区二区三区在线视频 | 国产精品麻豆欧美日韩ww | 日韩精品视频免费看 | 性三级视频 | 国产又爽又黄的激情精品视频 | 成年人视频在线免费看 | 白白色视频在线 | 在线色网址| 在线观看国产亚洲 | 欧美变态口味重另类 | 婷婷开心激情网 | 国产91精品久久久 | 成人av一区二区在线观看 | 一区三区视频在线观看 | 日批视频免费观看 | 波多野结衣在线播放视频 | 久久嗨| www四虎 | 少妇无码一区二区三区 | 亚洲人成网站999久久久综合 | 欧美在线精品一区 | 欧美精品性视频 | 狂野欧美 | 极品美女开粉嫩精品 | 在线射 | 成人精品动漫 | 精品91av | 日韩成人激情 | 激情另类小说 | 成人激情久久 | 国产18禁黄网站免费观看 | jizz黑人 | 成人依依 | 插插看| 国产精品99久久久久久一二区 | 国产日韩欧美精品在线观看 | 亚洲色图偷 | 亚洲精品一区三区三区在线观看 | 日本亚洲最大的色成网站www | 伊人伊人鲁 | 欧美色激情| 国产猛男猛女超爽免费视频 | 韩国三级视频在线 | 成人夜间视频 | 最新久久久| 前任攻略在线观看免费完整版 | 中文字幕伦理 | 在线观看国产视频 | 91麻豆视频网站 | 国产精品国产三级国产Av车上的 | 日韩精品久久久久久久的张开腿让 | 亚洲第一精品网站 | 欧美亚洲专区 | 午夜影视福利 | 一边摸一边做爽的视频17国产 | 欧美国产精品一区二区 |