谈谈Java中的锁
說到實現線程安全第一個想到的就應該是鎖,同步,synchronized這樣的字眼。但是synchronized是怎么實現同步呢,在JVM編譯的時候會在synchronized塊的前后分別添加一條指令,monitorenter/monitorexit,會在字節碼的異常路徑上也添加monitorexit。任何對象都有一個monitor與之關聯,線程執行到monitorenter的時候,會嘗試獲取對象的monitor,如果獲取到,那么就等于持有了這個對象的鎖,這個monitor有且僅有一個線程可以持有,其他線程嘗試獲取該monitor的時候只能等著或者阻塞。當執行完同步塊的代碼后,執行monitorexit會釋放掉改對象的monitor,并且喚醒在這個對象上阻塞的線程。那么這個對象到底是誰呢?我們一般會在三種情況下使用synchronized,
- 使用synchronized修飾的普通方法,此時鎖的對象調用此方法的類實例對象;
- 使用synchronized修飾的靜態方法,此時鎖的對象是類的Class對象;
- 使用synchronized修飾的同步塊,此時鎖的對象就是同步塊前的括號中的對象。
synchronized是JVM層面上支持的同步手段,在JUC的包中也有類可以實現加鎖的功能,ReentrantLock類是我們常用的另一種加鎖手段,這種鎖的時候需要我們手動創建ReentrantLock對象,顯示調用的ReentrantLock的lock方法和unlock方法來加鎖解鎖。注意unlock方法一般需要寫在try/finally塊的finally中,保證無論何時都要解鎖。除了和synchronized一樣的鎖功能,ReentrantLock還有一些高級特性,
- 等待可中斷,假如線程獲取鎖的時候需要等待很久,可以在等待的期間中斷出來,就是等不到就不等了,當然不等了肯定是沒獲取到鎖,但是線程可以去做別的事了。對應的方法為lockInterruptibly()。
- 公平鎖,公平鎖就是鎖多個線程嘗試獲取鎖的時候,等待時間最長的那個線程會先獲取到鎖。在創建ReentrantLock對象的時候傳入true參數得到的就是公平鎖。
- 鎖綁定多個條件,使用synchronized的時候只能對鎖的對象進行wait/notify,但是使用ReentrantLock,可以創建多個Condition,對多個Condition進行await/signal(多用于生產者消費者模式)。
我們可能又知道synchronized是一種重量級的鎖,重量級的鎖在同步問題中會使線程阻塞,而線程掛起和喚醒都需要操作系統轉入內核態來完成,毫無疑問這很耗費資源,。而ReentrantLock基本是使用volatile+CAS算法來實現的,這種實現也可以稱為樂觀鎖,對應著JVM中原來synchronized的實現就是悲觀鎖。這樣是不是就是鎖ReentrantLock比synchronized高效了呢,其實也不盡然。因為我們的JVM實現的鎖也一直在優化呀,這就要談到JVM一些鎖優化技術了,
- 自旋鎖和自適應自旋,想象一下這種情況,線程B需要進入同步塊的時候發現線程A持有鎖,按照之前的處理,B會掛起,等待A來喚醒,很可能B剛剛掛起A就釋放了鎖,這樣就很不爽,如果B多等一會兒就可以不用掛起了,這就是自旋鎖出現的原因。自旋鎖即碰到獲取鎖的情況會先讓CPU空轉一會兒,而不是放棄CPU的時間,可能很快就會得到鎖了。但是可能有的情況下線程A會持有鎖很長時間不放,那么B一直在這里空轉也是很耗費資源的,所以就加入了自適應的自旋,這樣JVM會根據同一個鎖上一次的自旋時間和鎖的擁有者的狀態來決定自旋的時間。
- 鎖消除和鎖粗化,這兩種優化技術主要是在編譯階段來解決的,鎖消除是編譯器對于代碼上同步,但是檢測到不存在共享數據競爭時,會自動去掉鎖,而鎖粗化是解決在一段代碼中頻繁加鎖解鎖的情況,雖然說同步塊的區域越小越好,但還是要避免在一段代碼中頻繁加鎖解鎖,這時編譯器會直接將鎖的范圍擴大。
- 偏向鎖,線程進入鎖的時候會使用CAS算法將鎖對象的狀態置為偏向狀態,這樣下次同一線程再次獲取鎖將不需要同步,消除同步,直接進入。但是如果有其他線程來獲取這個鎖,那么偏向模式就會結束,鎖會升級到輕量級鎖。
- 輕量級鎖,輕量級鎖是使用CAS算法來代替阻塞,線程進入鎖的時候使用CAS算法設置鎖對象的狀態,當其他線程也想進入鎖的時候會也會嘗試使用CAS算法來設置鎖對象的狀態,如果失敗說明其他線程已經獲取了鎖。自旋等待一段時間仍然沒有獲取鎖宣告失敗,此時鎖會升級到重量級鎖,線程進入阻塞狀態,然后持有鎖的線程在解鎖時會使用CAS算法更新鎖對象的狀態,如果成功,說明沒有線程來競爭鎖,失敗說明有線程競爭,然后需要喚醒阻塞的線程。
所以,我們在使用鎖的時候如果出于性能考慮完全不需要放棄synchronized,如果出于ReentrantLock的一些高級特性,那可以選擇ReentrantLock
posted on 2018-03-10 21:35 yihau 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/wangyihao/p/8542173.html
總結
- 上一篇: Firefox 网络调试工具
- 下一篇: mysql 性能剖析-profiles