www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]什么是鎖 在計(jì)算機(jī)科學(xué)中,鎖(lock)或互斥(mutex)是一種同步機(jī)制,用于在有許多執(zhí)行線程的環(huán)境中強(qiáng)制對(duì)資源的訪問(wèn)限制。鎖旨在強(qiáng)制實(shí)施互斥排他、并發(fā)控制策略。 ? ? ?鎖通常需要硬件支持才能有效實(shí)施。這種支持通常采取一個(gè)或多個(gè)原子指令的形式,如"test-an

什么是鎖

在計(jì)算機(jī)科學(xué)中,鎖(lock)或互斥(mutex)是一種同步機(jī)制,用于在有許多執(zhí)行線程的環(huán)境中強(qiáng)制對(duì)資源的訪問(wèn)限制。鎖旨在強(qiáng)制實(shí)施互斥排他、并發(fā)控制策略。
     鎖通常需要硬件支持才能有效實(shí)施。這種支持通常采取一個(gè)或多個(gè)原子指令的形式,如"test-and-set", "fetch-and-add" or "compare-and-swap"”。這些指令允許單個(gè)進(jìn)程測(cè)試鎖是否空閑,如果空閑,則通過(guò)單個(gè)原子操作獲取鎖。

公平鎖

  • 定義:就是很公平,在并發(fā)環(huán)境中,每個(gè)線程在獲取鎖時(shí)會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果為空,或者當(dāng)前線程線程是等待隊(duì)列的第一個(gè),就占有鎖,否則就會(huì)加入到等待隊(duì)列中,以后會(huì)按照FIFO的規(guī)則從隊(duì)列中取到自己。

  • 優(yōu)點(diǎn):所有的線程都能得到資源,不會(huì)餓死在隊(duì)列中。

  • 缺點(diǎn):吞吐量會(huì)下降很多,隊(duì)列里面除了第一個(gè)線程,其他的線程都會(huì)阻塞,cpu喚醒阻塞線程的開(kāi)銷(xiāo)會(huì)很大。

  • 公平鎖獲取鎖例子

 1 /**
2     *     true 表示 ReentrantLock 的公平鎖
3     */

4    private ReentrantLock lock = new ReentrantLock(true);
5
6    public   void testFail(){
7        try {
8            lock.lock();
9            System.out.println(Thread.currentThread().getName() +"獲得了鎖");
10        }finally {
11            lock.unlock();
12        }
13    }
14    public static void main(String[] args) {
15        FairLockTest fairLock = new FairLockTest();
16        Runnable runnable = () -> {
17           System.out.println(Thread.currentThread().getName()+"啟動(dòng)");
18            fairLock.testFail();
19        };
20        Thread[] threadArray = new Thread[10];
21        for (int i=0; i<10; i++) {
22            threadArray[i] = new Thread(runnable);
23        }
24        for (int i=0; i<10; i++) {
25            threadArray[i].start();
26        }
27    }

運(yùn)行結(jié)果

 1Thread-1啟動(dòng)
2Thread-1獲得了鎖
3Thread-3啟動(dòng)
4Thread-3獲得了鎖
5Thread-5啟動(dòng)
6Thread-5獲得了鎖
7Thread-2啟動(dòng)
8Thread-2獲得了鎖
9Thread-4啟動(dòng)
10Thread-4獲得了鎖
11Thread-6啟動(dòng)
12Thread-6獲得了鎖
13Thread-10啟動(dòng)
14Thread-8啟動(dòng)
15Thread-10獲得了鎖
16Thread-9啟動(dòng)
17Thread-7啟動(dòng)
18Thread-8獲得了鎖
19Thread-9獲得了鎖
20Thread-7獲得了鎖

看到結(jié)果里面獲得鎖的順序和線程啟動(dòng)順序是一致的,這就是公平鎖。

非公平鎖

  • 定義:線程加鎖時(shí)直接嘗試獲取鎖,獲取不到就自動(dòng)到隊(duì)尾等待。

  • 優(yōu)點(diǎn):非公平鎖性能高于公平鎖性能,非公平鎖能更充分的利用cpu的時(shí)間片,盡量的減少cpu空閑的狀態(tài)時(shí)間。

  • 缺點(diǎn):可能導(dǎo)致隊(duì)列中間的線程一直獲取不到鎖或者長(zhǎng)時(shí)間獲取不到鎖,導(dǎo)致餓死。

  • 非公平鎖列子:只需要將上面公平鎖的代碼改為new ReentrantLock(false);
    運(yùn)行結(jié)果

 1Thread-1啟動(dòng)
2Thread-0啟動(dòng)
3Thread-2啟動(dòng)
4Thread-3啟動(dòng)
5Thread-4啟動(dòng)
6Thread-8啟動(dòng)
7Thread-7啟動(dòng)
8Thread-6啟動(dòng)
9Thread-1獲得了鎖
10Thread-0獲得了鎖
11Thread-5啟動(dòng)
12Thread-5獲得了鎖
13Thread-2獲得了鎖
14Thread-3獲得了鎖
15Thread-4獲得了鎖
16Thread-8獲得了鎖
17Thread-7獲得了鎖
18Thread-6獲得了鎖
19Thread-9啟動(dòng)
20Thread-9獲得了鎖

線程啟動(dòng)順序是1、0、2、3、 4、 8 、7 、6 、5 、9,獲得鎖的順序卻是1 、0 、5 、2 、3 、4  、8 、7 、6 、9,這就是非公平鎖,它不保證先排隊(duì)嘗試去獲取鎖的線程一定能先拿到鎖。

重入鎖

  • 定義:- 可重入鎖指的是可重復(fù)可遞歸調(diào)用的鎖,在外層使用鎖之后,在內(nèi)層仍然可以使用,并且不發(fā)生死鎖(前提得是同一個(gè)對(duì)象或者class),這樣的鎖就叫做可重入鎖。ReentrantLock和synchronized都是可重入鎖
    下面是一個(gè)synchronized重入鎖的列子:

 1public class ReentrantLockTest {
2
3
4    public static void main(String[] args){
5        for (int i = 0; i < 10; i++) {
6           new Thread(() -> A()).start();
7        }
8    }
9    public static   synchronized void  A(){
10        System.out.println(Thread.currentThread().getName());
11        B();
12    }
13    public static synchronized void  B(){
14        System.out.println(Thread.currentThread().getName());
15    }
16}

輸出:

1Thread-1
2Thread-1
3Thread-0
4Thread-0

A方法和B方法同時(shí)輸出了線程名稱(chēng),表明即使遞歸使用synchronized也沒(méi)有發(fā)生死鎖,證明其是可重入的。

讀寫(xiě)鎖

百度百科定義的讀寫(xiě)鎖是:

讀寫(xiě)鎖實(shí)際是一種特殊的自旋鎖,它把對(duì)共享資源的訪問(wèn)者劃分成讀者和寫(xiě)者,讀者只對(duì)共享資源進(jìn)行讀訪問(wèn),寫(xiě)者則需要對(duì)共享資源進(jìn)行寫(xiě)操作。

  • 與傳統(tǒng)鎖不同的是讀寫(xiě)鎖的規(guī)則是可以共享讀,但只能一個(gè)寫(xiě),總結(jié)起來(lái)為:讀讀不互斥,讀寫(xiě)互斥,寫(xiě)寫(xiě)互斥,而一般的獨(dú)占鎖是:讀讀互斥,讀寫(xiě)互斥,寫(xiě)寫(xiě)互斥,而場(chǎng)景中往往讀遠(yuǎn)遠(yuǎn)大于寫(xiě),讀寫(xiě)鎖就是為了這種優(yōu)化而創(chuàng)建出來(lái)的一種機(jī)制。注意是讀遠(yuǎn)遠(yuǎn)大于寫(xiě),一般情況下獨(dú)占鎖的效率低來(lái)源于高并發(fā)下對(duì)臨界區(qū)的激烈競(jìng)爭(zhēng)導(dǎo)致線程上下文切換。因此當(dāng)并發(fā)不是很高的情況下,讀寫(xiě)鎖由于需要額外維護(hù)讀鎖的狀態(tài),可能還不如獨(dú)占鎖的效率高。因此需要根據(jù)實(shí)際情況選擇使用。

  • Java里面ReentrantReadWriteLock讀寫(xiě)鎖特性
        公平選擇性: 支持非公平(默認(rèn))和公平的鎖獲取方式,吞吐量還是非公平優(yōu)于公平。
        重進(jìn)入: 讀鎖和寫(xiě)鎖都支持線程重進(jìn)入。
        鎖降級(jí): 鎖降級(jí)是指把持?。ó?dāng)前擁有的)寫(xiě)鎖,再獲取到讀鎖,隨后釋放(先前擁有的)寫(xiě)鎖的過(guò)程。

樂(lè)觀鎖、悲觀鎖

  • 樂(lè)觀鎖:樂(lè)觀鎖總是認(rèn)為不存在并發(fā)問(wèn)題,每次去取數(shù)據(jù)的時(shí)候,總認(rèn)為不會(huì)有其他線程對(duì)數(shù)據(jù)進(jìn)行修改,因此不會(huì)上鎖。但是在更新時(shí)會(huì)判斷其他線程在這之前有沒(méi)有對(duì)數(shù)據(jù)進(jìn)行修改,一般會(huì)使用“數(shù)據(jù)版本機(jī)制”或“CAS操作”來(lái)實(shí)現(xiàn)。

  • 悲觀鎖: 悲觀鎖認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,一定會(huì)發(fā)生修改的,哪怕沒(méi)有修改,也會(huì)認(rèn)為修改。因此對(duì)于同一份數(shù)據(jù)的并發(fā)操作,悲觀鎖采取加鎖的形式。悲觀的認(rèn)為,不加鎖并發(fā)操作一定會(huì)出問(wèn)題。典型的數(shù)據(jù)庫(kù)的查詢(xún) for update。

    • 在對(duì)任意記錄進(jìn)行修改前,先嘗試為該記錄加上排他鎖(exclusive locking)。

    • 如果加鎖失敗,說(shuō)明該記錄正在被修改,那么當(dāng)前查詢(xún)可能要等待或者拋出異常。具體響應(yīng)方式由開(kāi)發(fā)者根據(jù)實(shí)際需要決定。

    • 如果成功加鎖,那么就可以對(duì)記錄做修改,事務(wù)完成后就會(huì)解鎖了。期間如果有其他對(duì)該記錄做修改或加排他鎖的操作,都會(huì)等待我們解鎖或直接拋出異常。

分段鎖

分段鎖其實(shí)是一種鎖的設(shè)計(jì),并不是具體的一種鎖,對(duì)jdk1.7 及以前的ConcurrentHashMap而言,其并發(fā)的實(shí)現(xiàn)就是通過(guò)分段鎖的形式來(lái)實(shí)現(xiàn)高效的并發(fā)操作。分段鎖的設(shè)計(jì)目的是細(xì)化鎖的粒度,當(dāng)操作不需要更新整個(gè)數(shù)組的時(shí)候,就僅僅針對(duì)數(shù)組中的一項(xiàng)進(jìn)行加鎖操作。

自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的線程不會(huì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會(huì)消耗CPU。

偏向鎖、輕量級(jí)鎖、重量級(jí)鎖

 這三種鎖是指鎖的狀態(tài),并且是針對(duì)Synchronized。在Java 5通過(guò)引入鎖升級(jí)的機(jī)制來(lái)實(shí)現(xiàn)高效Synchronized。這三種鎖的狀態(tài)是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的。
 

  • 偏向鎖:是指一段同步代碼一直被一個(gè)線程所訪問(wèn),那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)。

  • 輕量級(jí)鎖:是指當(dāng)鎖是偏向鎖的時(shí)候,被另一個(gè)線程所訪問(wèn),偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線程會(huì)通過(guò)自旋的形式嘗試獲取鎖,不會(huì)阻塞,提高性能。

  • 重量級(jí)鎖:是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候,另一個(gè)線程雖然是自旋,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋一定次數(shù)的時(shí)候,還沒(méi)有獲取到鎖,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖。重量級(jí)鎖會(huì)讓他申請(qǐng)的線程進(jìn)入阻塞,性能降低。

獨(dú)享鎖、共享鎖

  •  獨(dú)享鎖是指該鎖一次只能被一個(gè)線程所持有。

  •  共享鎖是指該鎖可被多個(gè)線程所持有。
    對(duì)于Java ReentrantLock而言,其是獨(dú)享鎖。但是對(duì)于Lock的另一個(gè)實(shí)現(xiàn)類(lèi)ReadWriteLock,其讀鎖是共享鎖,其寫(xiě)鎖是獨(dú)享鎖。 讀鎖的共享鎖可保證并發(fā)讀是非常高效的,讀寫(xiě),寫(xiě)讀,寫(xiě)寫(xiě)的過(guò)程是互斥的。獨(dú)享鎖與共享鎖也是通過(guò)AQS來(lái)實(shí)現(xiàn)的,通過(guò)實(shí)現(xiàn)不同的方法,來(lái)實(shí)現(xiàn)獨(dú)享或者共享。對(duì)于Synchronized而言,當(dāng)然是獨(dú)享鎖。

    參考文章
    https://blog.csdn.net/qiuwenjie123/article/details/79950532
    https://segmentfault.com/q/1010000009659039
    https://blog.csdn.net/qq_43519310/article/details/100107346
    https://blog.csdn.net/u010648018/article/details/79750608
    https://www.cnblogs.com/hustzzl/p/9343797.html
    http://ifeve.com/locks/
    http://ifeve.com/locks/

特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒(méi)關(guān)注的小伙伴,可以長(zhǎng)按關(guān)注一下:

史上最全 Java 中各種鎖的介紹

長(zhǎng)按訂閱更多精彩▼

史上最全 Java 中各種鎖的介紹

如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉