溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

synchronized和Lock有什么區(qū)別

發(fā)布時(shí)間:2020-11-19 13:52:19 來(lái)源:億速云 閱讀:147 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹synchronized和Lock有什么區(qū)別,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

區(qū)別:1、lock是一個(gè)接口,而synchronized是java的一個(gè)關(guān)鍵字。2、synchronized在發(fā)生異常時(shí)會(huì)自動(dòng)釋放占有的鎖,因此不會(huì)出現(xiàn)死鎖;而lock發(fā)生異常時(shí),不會(huì)主動(dòng)釋放占有的鎖,必須手動(dòng)來(lái)釋放鎖,可能引起死鎖的發(fā)生。

在分布式開(kāi)發(fā)中,鎖是線程控制的重要途徑。Java為此也提供了2種鎖機(jī)制,synchronized和lock。

0、synchronized實(shí)現(xiàn)原理

Java中每一個(gè)對(duì)象都可以作為鎖,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):

  • 普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象

  • 靜態(tài)同步方法,鎖是當(dāng)前類(lèi)的class對(duì)象

  • 同步方法塊,鎖是括號(hào)里面的對(duì)象
    當(dāng)一個(gè)線程訪問(wèn)同步代碼塊時(shí),它首先是需要得到鎖,當(dāng)退出或者拋出異常時(shí)必須要釋放鎖,那么它是如何來(lái)實(shí)現(xiàn)這個(gè)機(jī)制的呢?我們先看一段簡(jiǎn)單的代碼:

package cn.alibab.javap;public class SynchronizedTest {

    public synchronized void test1(){

    }    public void test2(){        synchronized (this){

        }
    }
}

利用javap工具(javap是java編譯之后的class文件的分解器)查看生成的class文件信息來(lái)分析Synchronized的實(shí)現(xiàn)

synchronized和Lock有什么區(qū)別

synchronized和Lock有什么區(qū)別
從上面可以看出,同步代碼塊是使用monitorenter和monitorexit指令實(shí)現(xiàn)的,同步方法(在這看不出來(lái)需要看JVM底層實(shí)現(xiàn))依靠的是方法修飾符上的ACC_SYNCHRONIZED實(shí)現(xiàn)。

同步代碼塊:monitorenter指令是在編譯后插入到同步代碼塊的開(kāi)始位置,monitorexit指令插入到同步代碼塊的結(jié)束位置,JVM需要保證每一個(gè)monitorenter都有一個(gè)monitorexit與之相對(duì)應(yīng)。任何對(duì)象都有一個(gè)monitor與之相關(guān)聯(lián),當(dāng)且一個(gè)monitor被持有之后,他將處于鎖定狀態(tài)。線程執(zhí)行到monitorenter指令時(shí),將會(huì)嘗試獲取對(duì)象所對(duì)應(yīng)的monitor所有權(quán),即嘗試獲取對(duì)象的鎖;【摘自并發(fā)編程藝術(shù)】

同步方法:synchronized方法則會(huì)被翻譯成普通的方法調(diào)用和返回指令如:invokevirtual、areturn指令,在VM字節(jié)碼層面并沒(méi)有任何特別的指令來(lái)實(shí)現(xiàn)被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags字段中的synchronized標(biāo)志位置1,表示該方法是同步方法并使用調(diào)用該方法的對(duì)象或該方法所屬的Class在JVM的內(nèi)部對(duì)象表示Klass做為鎖對(duì)象。(摘自:http://www.cnblogs.com/javaminer/p/3889023.html)

synchronized和lock的區(qū)別

synchronized和Lock有什么區(qū)別
區(qū)別如下:

  • 來(lái)源:
    lock是一個(gè)接口,而synchronized是java的一個(gè)關(guān)鍵字,synchronized是內(nèi)置的語(yǔ)言實(shí)現(xiàn);

  • 異常是否釋放鎖:
    synchronized在發(fā)生異常時(shí)候會(huì)自動(dòng)釋放占有的鎖,因此不會(huì)出現(xiàn)死鎖;而lock發(fā)生異常時(shí)候,不會(huì)主動(dòng)釋放占有的鎖,必須手動(dòng)unlock來(lái)釋放鎖,可能引起死鎖的發(fā)生。(所以最好將同步代碼塊用try catch包起來(lái),finally中寫(xiě)入unlock,避免死鎖的發(fā)生。)

  • 是否響應(yīng)中斷
    lock等待鎖過(guò)程中可以用interrupt來(lái)中斷等待,而synchronized只能等待鎖的釋放,不能響應(yīng)中斷;

  • 是否知道獲取鎖
    Lock可以通過(guò)trylock來(lái)知道有沒(méi)有獲取鎖,而synchronized不能;

  • Lock可以提高多個(gè)線程進(jìn)行讀操作的效率。(可以通過(guò)readwritelock實(shí)現(xiàn)讀寫(xiě)分離)

  • 在性能上來(lái)說(shuō),如果競(jìng)爭(zhēng)資源不激烈,兩者的性能是差不多的,而當(dāng)競(jìng)爭(zhēng)資源非常激烈時(shí)(即有大量線程同時(shí)競(jìng)爭(zhēng)),此時(shí)Lock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized。所以說(shuō),在具體使用時(shí)要根據(jù)適當(dāng)情況選擇。

  • synchronized使用Object對(duì)象本身的wait 、notify、notifyAll調(diào)度機(jī)制,而Lock可以使用Condition進(jìn)行線程之間的調(diào)度,

//Condition定義了等待/通知兩種類(lèi)型的方法
Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();...condition.await();...condition.signal();
condition.signalAll();

1、synchronized和lock的用法區(qū)別

synchronized:在需要同步的對(duì)象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括號(hào)中表示需要鎖的對(duì)象。

lock:一般使用ReentrantLock類(lèi)做為鎖。在加鎖和解鎖處需要通過(guò)lock()和unlock()顯示指出。所以一般會(huì)在finally塊中寫(xiě)unlock()以防死鎖。

2、synchronized和lock性能區(qū)別

synchronized是托管給JVM執(zhí)行的,
而lock是java寫(xiě)的控制鎖的代碼。

在Java1.5中,synchronize是性能低效的。因?yàn)檫@是一個(gè)重量級(jí)操作,需要調(diào)用操作接口,導(dǎo)致有可能加鎖消耗的系統(tǒng)時(shí)間比加鎖以外的操作還多。相比之下使用Java提供的Lock對(duì)象,性能更高一些。

但是到了Java1.6,發(fā)生了變化。synchronize在語(yǔ)義上很清晰,可以進(jìn)行很多優(yōu)化,有適應(yīng)自旋,鎖消除,鎖粗化,輕量級(jí)鎖,偏向鎖等等。導(dǎo)致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他們也更支持synchronize,在未來(lái)的版本中還有優(yōu)化余地。

2種機(jī)制的具體區(qū)別:
synchronized原始采用的是CPU悲觀鎖機(jī)制,即線程獲得的是獨(dú)占鎖。獨(dú)占鎖意味著其他線程只能依靠阻塞來(lái)等待線程釋放鎖。而在CPU轉(zhuǎn)換線程阻塞時(shí)會(huì)引起線程上下文切換,當(dāng)有很多線程競(jìng)爭(zhēng)鎖的時(shí)候,會(huì)引起CPU頻繁的上下文切換導(dǎo)致效率很低。

而Lock用的是樂(lè)觀鎖方式。所謂樂(lè)觀鎖就是,每次不加鎖而是假設(shè)沒(méi)有沖突而去完成某項(xiàng)操作,如果因?yàn)闆_突失敗就重試,直到成功為止。樂(lè)觀鎖實(shí)現(xiàn)的機(jī)制就是CAS操作(Compare and Swap)。我們可以進(jìn)一步研究ReentrantLock的源代碼,會(huì)發(fā)現(xiàn)其中比較重要的獲得鎖的一個(gè)方法是compareAndSetState。這里其實(shí)就是調(diào)用的CPU提供的特殊指令。

現(xiàn)代的CPU提供了指令,可以自動(dòng)更新共享數(shù)據(jù),而且能夠檢測(cè)到其他線程的干擾,而 compareAndSet() 就用這些代替了鎖定。這個(gè)算法稱(chēng)作非阻塞算法,意思是一個(gè)線程的失敗或者掛起不應(yīng)該影響其他線程的失敗或掛起的算法。

3、synchronized和lock用途區(qū)別

synchronized原語(yǔ)和ReentrantLock在一般情況下沒(méi)有什么區(qū)別,但是在非常復(fù)雜的同步應(yīng)用中,請(qǐng)考慮使用ReentrantLock,特別是遇到下面2種需求的時(shí)候。

1.某個(gè)線程在等待一個(gè)鎖的控制權(quán)的這段時(shí)間需要中斷
2.需要分開(kāi)處理一些wait-notify,ReentrantLock里面的Condition應(yīng)用,能夠控制notify哪個(gè)線程
3.具有公平鎖功能,每個(gè)到來(lái)的線程都將排隊(duì)等候

下面細(xì)細(xì)道來(lái)……

先說(shuō)第一種情況,ReentrantLock的lock機(jī)制有2種,忽略中斷鎖和響應(yīng)中斷鎖,這給我們帶來(lái)了很大的靈活性。比如:如果A、B 2個(gè)線程去競(jìng)爭(zhēng)鎖,A線程得到了鎖,B線程等待,但是A線程這個(gè)時(shí)候?qū)嵲谟刑嗍虑橐幚?,就是一直不返回,B線程可能就會(huì)等不及了,想中斷自己,不再等待這個(gè)鎖了,轉(zhuǎn)而處理其他事情。這個(gè)時(shí)候ReentrantLock就提供了2種機(jī)制:可中斷/可不中斷
第一,B線程中斷自己(或者別的線程中斷它),但是ReentrantLock不去響應(yīng),繼續(xù)讓B線程等待,你再怎么中斷,我全當(dāng)耳邊風(fēng)(synchronized原語(yǔ)就是如此);
第二,B線程中斷自己(或者別的線程中斷它),ReentrantLock處理了這個(gè)中斷,并且不再等待這個(gè)鎖的到來(lái),完全放棄。

以上是synchronized和Lock有什么區(qū)別的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI