您好,登錄后才能下訂單哦!
這篇文章主要介紹了簡單了解synchronized和lock的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
類別 | synchronized | Lock |
---|---|---|
存在層次 | Java的關(guān)鍵字 | 一個(gè)類 |
鎖的釋放 | 1.以獲取鎖的線程執(zhí)行代碼同步代碼,釋放鎖。 2,線程執(zhí)行發(fā)生異常,jvm會(huì)讓線程釋放鎖 |
在finally中必須釋放鎖,不然容易造成線程死鎖 |
鎖的獲取 | 假設(shè)A線程獲得鎖,B線程等待,如果A線程阻塞,則B會(huì)一直等 | 分情況而定,Lock有多個(gè)獲取鎖的方式,線程不用一直等 |
鎖狀態(tài) | 無法判斷 | 可判斷 |
鎖類型 | 可重入,不可中斷,非公平 | 可重入,可判斷,可公平 |
性能 | 少量同步 | 大量同步 |
1.Lock
Lock的幾個(gè)方法
2. synchronized
3.樂觀鎖和悲觀鎖
樂觀鎖( Optimistic Locking )
相對(duì)悲觀鎖而言,樂觀鎖機(jī)制采取了更加寬松的加鎖機(jī)制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機(jī)制實(shí)現(xiàn),以保證操作最大程度的獨(dú)占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對(duì)長事務(wù)而言,這樣的開銷往往無法承受。而樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。樂觀鎖,大多是基于數(shù)據(jù)版本( Version )記錄機(jī)制實(shí)現(xiàn)。
何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí),在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個(gè) “version” 字段來實(shí)現(xiàn)。讀取出數(shù)據(jù)時(shí),將此版本號(hào)一同讀出,之后更新時(shí),對(duì)此版本號(hào)加一。此時(shí),將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對(duì)應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對(duì),如果提交的數(shù)據(jù)版本號(hào)大于數(shù)據(jù)庫表當(dāng)前版本號(hào),則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
悲觀鎖(Pessimistic Lock)
正如其名,具有強(qiáng)烈的獨(dú)占和排他特性。它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機(jī)制(也只有數(shù)據(jù)庫層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))。
悲觀鎖(適合多寫場景)
總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)阻塞直到它拿到鎖(共享資源每次只給一個(gè)線程使用,其它線程阻塞,用完后再把資源轉(zhuǎn)讓給其它線程)。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨(dú)占鎖就是悲觀鎖思想的實(shí)現(xiàn)
樂觀鎖(適合多讀場景)
總是假設(shè)最好的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)機(jī)制和CAS算法實(shí)現(xiàn)。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫提供的類似于write_condition機(jī)制,其實(shí)都是提供的樂觀鎖。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實(shí)現(xiàn)方式CAS實(shí)現(xiàn)的。(compare and swap)
樂觀鎖的缺點(diǎn)
4.Java線程阻塞的代價(jià)
java的線程是映射到操作系統(tǒng)原生線程之上的,如果要阻塞或喚醒一個(gè)線程就需要操作系統(tǒng)介入,需要在戶態(tài)與核心態(tài)之間切換,這種切換會(huì)消耗大量的系統(tǒng)資源,因?yàn)橛脩魬B(tài)與內(nèi)核態(tài)都有各自專用的內(nèi)存空間,專用的寄存器等,用戶態(tài)切換至內(nèi)核態(tài)需要傳遞給許多變量、參數(shù)給內(nèi)核,內(nèi)核也需要保護(hù)好用戶態(tài)在切換時(shí)的一些寄存器值、變量等,以便內(nèi)核態(tài)調(diào)用結(jié)束后切換回用戶態(tài)繼續(xù)工作。
如果線程狀態(tài)切換是一個(gè)高頻操作時(shí),這將會(huì)消耗很多CPU處理時(shí)間;
如果對(duì)于那些需要同步的簡單的代碼塊,獲取鎖掛起操作消耗的時(shí)間比用戶代碼執(zhí)行的時(shí)間還要長,這種同步策略顯然非常糟糕的。
synchronized會(huì)導(dǎo)致爭用不到鎖的線程進(jìn)入阻塞狀態(tài),所以說它是java語言中一個(gè)重量級(jí)的同步操縱,被稱為重量級(jí)鎖,為了緩解上述性能問題,JVM從1.5開始,引入了輕量鎖與偏向鎖,默認(rèn)啟用了自旋鎖,他們都屬于樂觀鎖。
5.重量級(jí)鎖和輕量級(jí)鎖
1. 自旋鎖
自旋鎖原理非常簡單,如果持有鎖的線程能在很短時(shí)間內(nèi)釋放鎖資源,那么那些等待競爭鎖的線程就不需要做內(nèi)核態(tài)和用戶態(tài)之間的切換進(jìn)入阻塞掛起狀態(tài),它們只需要等一等(自旋),等持有鎖的線程釋放鎖后即可立即獲取鎖,這樣就避免用戶線程和內(nèi)核的切換的消耗。
但是線程自旋是需要消耗cup的,說白了就是讓cup在做無用功,如果一直獲取不到鎖,那線程也不能一直占用cup自旋做無用功,所以需要設(shè)定一個(gè)自旋等待的最大時(shí)間。
如果持有鎖的線程執(zhí)行的時(shí)間超過自旋等待的最大時(shí)間扔沒有釋放鎖,就會(huì)導(dǎo)致其它爭用鎖的線程在最大等待時(shí)間內(nèi)還是獲取不到鎖,這時(shí)爭用線程會(huì)停止自旋進(jìn)入阻塞狀態(tài)。
自旋鎖的優(yōu)缺點(diǎn)
自旋鎖盡可能的減少線程的阻塞,這對(duì)于鎖的競爭不激烈,且占用鎖時(shí)間非常短的代碼塊來說性能能大幅度的提升,因?yàn)樽孕南臅?huì)小于線程阻塞掛起再喚醒的操作的消耗,這些操作會(huì)導(dǎo)致線程發(fā)生兩次上下文切換!
但是如果鎖的競爭激烈,或者持有鎖的線程需要長時(shí)間占用鎖執(zhí)行同步塊,這時(shí)候就不適合使用自旋鎖了,因?yàn)樽孕i在獲取鎖前一直都是占用cpu做無用功,占著XX不XX,同時(shí)有大量線程在競爭一個(gè)鎖,會(huì)導(dǎo)致獲取鎖的時(shí)間很長,線程自旋的消耗大于線程阻塞掛起操作的消耗,其它需要cup的線程又不能獲取到cpu,造成cpu的浪費(fèi)。所以這種情況下我們要關(guān)閉自旋鎖;
自旋鎖時(shí)間閾值
自旋鎖的目的是為了占著CPU的資源不釋放,等到獲取到鎖立即進(jìn)行處理。但是如何去選擇自旋的執(zhí)行時(shí)間呢?如果自旋執(zhí)行時(shí)間太長,會(huì)有大量的線程處于自旋狀態(tài)占用CPU資源,進(jìn)而會(huì)影響整體系統(tǒng)的性能。因此自旋的周期選的額外重要!
JVM對(duì)于自旋周期的選擇,jdk1.5這個(gè)限度是一定的寫死的,在1.6引入了適應(yīng)性自旋鎖,適應(yīng)性自旋鎖意味著自旋的時(shí)間不在是固定的了,而是由前一次在同一個(gè)鎖上的自旋時(shí)間以及鎖的擁有者的狀態(tài)來決定,基本認(rèn)為一個(gè)線程上下文切換的時(shí)間是最佳的一個(gè)時(shí)間,同時(shí)JVM還針對(duì)當(dāng)前CPU的負(fù)荷情況做了較多的優(yōu)化
自旋鎖的開啟
JDK1.7后,去掉此參數(shù),由jvm控制
2.重量級(jí)鎖(synchronized)
synchronized的作用
synchronized的實(shí)現(xiàn)
3.偏向鎖
Java偏向鎖(Biased Locking)是Java6引入的一項(xiàng)多線程優(yōu)化。
偏向鎖,顧名思義,它會(huì)偏向于第一個(gè)訪問鎖的線程,如果在運(yùn)行過程中,同步鎖只有一個(gè)線程訪問,不存在多線程爭用的情況,則線程是不需要觸發(fā)同步的,這種情況下,就會(huì)給線程加一個(gè)偏向鎖。
如果在運(yùn)行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會(huì)被掛起,JVM會(huì)消除它身上的偏向鎖,將鎖恢復(fù)到標(biāo)準(zhǔn)的輕量級(jí)鎖。
4.輕量級(jí)鎖
輕量級(jí)鎖是由偏向所升級(jí)來的,偏向鎖運(yùn)行在一個(gè)線程進(jìn)入同步塊的情況下,當(dāng)?shù)诙€(gè)線程加入鎖爭用的時(shí)候,偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖;
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。