區別:1、lock是一個接口,而synchronized是java的一個關鍵字。 2.synchronized在發生異常時會自動釋放佔有的鎖,因此不會出現死鎖;而lock發生異常時,不會主動釋放佔有的鎖,必須手動來釋放鎖,可能引起死鎖的發生。
在分散式開發中,鎖定是執行緒控制的重要途徑。 Java為此也提供了2種鎖定機制,synchronized和lock。
0、synchronized實作原理
Java中每個物件都可以當作鎖,這是synchronized實作同步的基礎:
#普通同步方法,鎖定是目前實例物件
#靜態同步方法,鎖定是目前類別的class物件
同步方法區塊,鎖是括號裡面的物件
當一個執行緒存取同步程式碼區塊時,它首先是需要被鎖,當退出或拋出例外時必須要釋放鎖,那麼它是如何來實現這個機制的呢?我們先看一段簡單的程式碼:
package cn.alibab.javap;public class SynchronizedTest { public synchronized void test1(){ } public void test2(){ synchronized (this){ } } }
利用javap工具(javap是java編譯之後的class檔案的分解器)查看產生的class檔案資訊來分析Synchronized的實作
從上面可以看出,同步程式碼區塊是使用monitorenter和monitorexit指令實現的,同步方法(在這看不出來需要看JVM底層實現)依賴的是方法修飾符上的ACC_SYNCHRONIZED實作。
同步程式碼區塊:monitorenter指令是在編譯後插入到同步程式碼區塊的起始位置,monitorexit指令插入到同步程式碼區塊的結束位置,JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何物件都有一個monitor與之相關聯,當且一個monitor被持有之後,他將處於鎖定狀態。當執行緒執行到monitorenter指令時,將會嘗試取得物件所對應的monitor所有權,即嘗試取得物件的鎖定;【摘自並發程式設計藝術】
同步方法:synchronized方法則會被翻譯成普通的方法呼叫和返回指令如:invokevirtual、areturn指令,在VM字節碼層面並沒有任何特別的指令來實現被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags欄位中的synchronized標誌位置1,表示該方法是同步方法並使用呼叫該方法的物件或該方法所屬的Class在JVM的內部物件表示Klass做為鎖定物件。 (摘自:http://www.cnblogs.com/javaminer/p/3889023.html)
synchronized與lock的差別
差異如下:
lock是一個接口,而synchronized是java的一個關鍵字,synchronized是內建的語言實作;
#異常是否釋放鎖:
synchronized在發生異常時候會自動釋放佔有的鎖,因此不會出現死鎖;而lock發生異常時候,不會主動釋放佔有的鎖,必須手動unlock來釋放鎖,可能引起死鎖的發生。 (所以最好將同步程式碼區塊用try catch包起來,finally中寫入unlock,避免死鎖的發生。)是否知道取得鎖定
Lock可以透過trylock來知道有沒有取得鎖,而synchronized不能;Lock可以提高多個執行緒進行讀取操作的效率。 (可以透過readwritelock實現讀寫分離)在效能上來說,如果競爭資源不激烈,兩者的效能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。
//Condition定义了等待/通知两种类型的方法 Lock lock=new ReentrantLock(); Condition condition=lock.newCondition();...condition.await();...condition.signal(); condition.signalAll();
在Java1.5中,synchronize是效能低效的。因為這是一個重量級操作,需要呼叫操作接口,導致有可能加鎖消耗的系統時間比加鎖以外的操作還多。相較之下使用Java提供的Lock對象,效能更高一些。
但是到了Java1.6,發生了變化。 synchronize在語意上很清晰,可以進行很多優化,有適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在Java1.6上synchronize的效能並不比Lock差。官方也表示,他們也更支援synchronize,在未來的版本還有優化空間。
2種機制的具體差異:
synchronized原始採用的是CPU悲觀鎖定機制,即執行緒取得的是獨佔鎖定。 獨佔鎖定意味著其他執行緒只能依靠阻塞來等待執行緒釋放鎖定。而在CPU轉換執行緒阻塞時會造成執行緒上下文切換,當有很多執行緒競爭鎖的時候,會造成CPU頻繁的上下文切換導致效率很低。
而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有衝突而去完成某項操作,如果因為衝突失敗就重試,直到成功為止。樂觀鎖實現的機制就是CAS操作(Compare and Swap)。我們可以進一步研究ReentrantLock的原始碼,會發現其中比較重要的獲得鎖定的一個方法是compareAndSetState。這裡其實就是所呼叫的CPU提供的特殊指令。
現代的CPU提供了指令,可以自動更新共享數據,而且能夠偵測到其他執行緒的干擾,而 compareAndSet() 就用這些取代了鎖定。這個演算法稱作非阻塞演算法,意思是一個執行緒的失敗或掛起不應該影響其他執行緒的失敗或掛起的演算法。
3、synchronized和lock用途區別
synchronized原語和ReentrantLock在一般情況下沒有什麼區別,但是在非常複雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。
1.某個執行緒在等待一個鎖的控制權的這段時間需要中斷
2.需要分開處理一些wait-notify,ReentrantLock裡面的Condition應用,能夠控制notify哪個執行緒
3.具有公平鎖定功能,每個到來的線程都將排隊等候
下面細細道來…
先說第一種情況,ReentrantLock的lock機制有2種,忽略中斷鎖和回應中斷鎖,這給我們帶來了很大的靈活性。例如:如果A、B 2個線程去競爭鎖,A線程得到了鎖,B線程等待,但是A線程這個時候實在有太多事情要處理,就是一直不返回,B線程可能就會等不及了,想中斷自己,不再等待這個鎖了,轉而處理其他事情。這時候ReentrantLock就提供了2種機制:可中斷/可不中斷
第一,B線程中斷自己(或者別的線程中斷它),但是ReentrantLock不去回應,繼續讓B線程等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);
第二,B線程中斷自己(或者別的線程中斷它),ReentrantLock處理了這個中斷,並且不再等待這個鎖的到來,完全放棄。
更多程式相關知識,請造訪:程式設計影片! !
以上是synchronized和Lock的差別是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!