synchronized和ReentrantLock的區別


轉載:http://houlinyan.iteye.com/blog/1112535

基本概念

1、ReentrantLock 擁有Synchronized相同的並發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候

     線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,

     如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷

     如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以后,中斷等待,而干別的事情

 

    ReentrantLock獲取鎖定與三種方式:
    a)  lock(), 如果獲取了鎖立即返回,如果別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖

    b) tryLock(), 如果獲取了鎖立即返回true,如果別的線程正持有鎖,立即返回false;

    c)tryLock(long timeout,TimeUnit unit),   如果獲取了鎖定立即返回true,如果別的線程正持有鎖,會等待參數給定的時間,在等待的過程中,如果獲取了鎖定,就返回true,如果等待超時,返回false;

    d) lockInterruptibly:如果獲取了鎖定立即返回,如果沒有獲取鎖定,當前線程處於休眠狀態,直到或者鎖定,或者當前線程被別的線程中斷

 

2、synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中

 

3、在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態;

 

下面內容 是轉載 http://zzhonghe.iteye.com/blog/826162

5.0的多線程任務包對於同步的性能方面有了很大的改進,在原有synchronized關鍵字的基礎上,又增加了ReentrantLock,以及各種Atomic類。了解其性能的優劣程度,有助與我們在特定的情形下做出正確的選擇。 

總體的結論先擺出來:  

synchronized: 
在資源競爭不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合適的。原因在於,編譯程序通常會盡可能的進行優化synchronize,另外可讀性非常好,不管用沒用過5.0多線程包的程序員都能理解。 

ReentrantLock: 
ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍。而ReentrantLock確還能維持常態。 

Atomic: 
和上面的類似,不激烈情況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優於ReentrantLock一倍左右。但是其有一個缺點,就是只能同步一個值,一段代碼中只能出現一個Atomic的變量,多於一個同步無效。因為他不能在多個Atomic之間同步。 


所以,我們寫同步的時候,優先考慮synchronized,如果有特殊需要,再進一步優化。ReentrantLock和Atomic如果用的不好,不僅不能提高性能,還可能帶來災難。

補充兩者喚醒線程方式+線程切換

只要線程可以在30到50次自旋里拿到鎖,那么Synchronized就不會升級為重量級鎖,而等待的線程也就不用被掛起,我們也就少了掛起和喚醒這個上下文切換的過程開銷.

但如果是ReentrantLock呢?不會自旋,而是直接被掛起,這樣一來,我們就很容易會多出線程上下文開銷的代價.當然,你也可以使用tryLock(),但是這樣又出現了一個問題,你怎么知道tryLock的時間呢?在時間范圍里還好,假如超過了呢?

所以,在鎖被細化到如此程度上,使用Synchronized是最好的選擇了.這里再補充一句,Synchronized和ReentrantLock他們的開銷差距是在釋放鎖時喚醒線程的數量,Synchronized是喚醒鎖池里所有的線程+剛好來訪問的線程,而ReentrantLock則是當前線程后進來的第一個線程+剛好來訪問的線程.

如果是線程並發量不大的情況下,那么Synchronized因為自旋鎖,偏向鎖,輕量級鎖的原因,不用將等待線程掛起,偏向鎖甚至不用自旋,所以在這種情況下要比ReentrantLock高效。

補充兩者為什么默認都是非公平鎖

ReentrantLock公平和非公平鎖的隊列都基於鎖內部維護的一個雙向鏈表,表結點Node的值就是每一個請求當前鎖的線程。

公平鎖則在於每次都是依次從隊首取值,嚴格按照線程啟動的順序來執行的,不允許插隊。

非公平鎖在等待鎖的過程中, 如果有任意新的線程妄圖獲取鎖,都是有很大的幾率直接獲取到鎖的,允許插隊。

默認情況下ReentrantLock是通過非公平鎖來進行同步的,包括synchronized關鍵字都是如此,因為這樣性能會更好。因為從線程進入了RUNNABLE狀態,可以執行開始,到實際線程執行是要比較久的時間的。而且,在一個鎖釋放之后,其他的線程會需要重新來獲取鎖。其中經歷了持有鎖的線程釋放鎖,其他線程從掛起恢復到RUNNABLE狀態,其他線程請求鎖,獲得鎖,線程執行,這一系列步驟。如果這個時候,存在一個線程直接請求鎖,可能就避開掛起到恢復RUNNABLE狀態的這段消耗,所以性能更優化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM