最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解java并發(fā)之重入鎖-ReentrantLock

 更新時(shí)間:2019年03月13日 15:37:27   作者:胖虎。。  
這篇文章主要介紹了java并發(fā)之重入鎖-ReentrantLock,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

目前主流的鎖有兩種,一種是synchronized,另一種就是ReentrantLock,JDK優(yōu)化到現(xiàn)在目前為止synchronized的性能已經(jīng)和重入鎖不分伯仲了,但是重入鎖的功能和靈活性要比這個(gè)關(guān)鍵字多的多,所以重入鎖是可以完全替代synchronized關(guān)鍵字的。下面就來介紹這個(gè)重入鎖。

正文

ReentrantLock重入鎖是Lock接口里最重要的實(shí)現(xiàn),也是在實(shí)際開發(fā)中應(yīng)用最多的一個(gè),我這篇文章更接近實(shí)際開發(fā)的應(yīng)用場景,為開發(fā)者提供直接上手應(yīng)用。所以不是所有方法我都講解,有些冷門的方法我不會(huì)介紹或一句帶過。

一、首先先看聲明一個(gè)重入鎖需要使用到那幾個(gè)構(gòu)造方法

public ReentrantLock() {
        sync = new NonfairSync();
    }
 
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

推薦聲明方式

private static ReentrantLock lock = new ReentrantLock(true);
private static ReentrantLock locka = new ReentrantLock();

重點(diǎn)說明:

ReentrantLock提供了兩個(gè)構(gòu)造方法,對應(yīng)兩種聲明方式。

第一種聲明的是公平鎖,所謂公平鎖,就是按照時(shí)間先后順序,使先等待的線程先得到鎖,而且,公平鎖不會(huì)產(chǎn)生饑餓鎖,也就是只要排隊(duì)等待,最終能等待到獲取鎖的機(jī)會(huì)。

第二種聲明的是非公平鎖,所謂非公平鎖就和公平鎖概念相反,線程等待的順序并不一定是執(zhí)行的順序,也就是后來進(jìn)來的線程可能先被執(zhí)行。

ReentrantLock默認(rèn)是非公平鎖,因?yàn)椋汗芥i實(shí)現(xiàn)了先進(jìn)先出的公平性,但是由于來一個(gè)線程就加入隊(duì)列中,往往都需要阻塞,再由阻塞變?yōu)檫\(yùn)行,這種上下文切換是非常好性能的。非公平鎖由于允許插隊(duì)所以,上下文切換少的多,性能比較好,保證的大的吞吐量,但是容易出現(xiàn)饑餓問題。所以實(shí)際生產(chǎn)也是較多的使用非公平鎖。

非公平鎖調(diào)用的是NonfairSync方法。

二、加入鎖之后lock方法到底是怎么處理的(只講非公平鎖)
剛才我們說如果是非公平鎖就調(diào)用NonfairSync方法,那我們就來看看這個(gè)方法都做來什么。

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
 
        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
 
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

重點(diǎn)說明:

讀前先知:ReentrantLock用state表示“持有鎖的線程已經(jīng)重復(fù)獲取該鎖的次數(shù)”。當(dāng)state(下文用狀態(tài)二子代替)等于0時(shí),表示當(dāng)前沒有線程持有鎖)。
第一步調(diào)用compareAndSetState方法,傳了第一參數(shù)是期望值0,第二個(gè)參數(shù)是實(shí)際值1,當(dāng)前這個(gè)方法實(shí)際是調(diào)用了unsafe.compareAndSwapInt實(shí)現(xiàn)CAS操作的,也就是上鎖之前狀態(tài)必須是0,如果是0調(diào)用setExclusiveOwnerThread方法

private transient Thread exclusiveOwnerThread;
 
    
    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

可以看出setExclusiveOwnerThread就是線程設(shè)置為當(dāng)前線程,此時(shí)說明有一名線程已經(jīng)拿到了鎖。大家都是CAS有三個(gè)值,如果舊值等于預(yù)期值,就把新值賦予上,所以當(dāng)前線程得到了鎖就會(huì)把狀態(tài)置為1。

第二步是compareAndSetState方法返回false時(shí),此時(shí)調(diào)用的是acquire方法,參數(shù)傳1

tryAcquire()方法實(shí)際是調(diào)用了nonfairTryAcquire()方法。

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
 
final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

注釋上說的很明白,請求獨(dú)占鎖,忽略所有中斷,至少執(zhí)行一次tryAcquire,如果成功就返回,否則線程進(jìn)入阻塞--喚醒兩種狀態(tài)切換中,直到tryAcquire成功。詳情見鏈接tryAcquire()、addWaiter()、acquireQueued()挨個(gè)分析。

 好,到日前為止大家清楚了lock()方法到調(diào)用過程,清楚了,為什么只有得到鎖的當(dāng)前線程才可以執(zhí)行,沒有得到的會(huì)在隊(duì)列里不停的利用CAS原理試圖得到鎖,CAS很高效,也就是,為什么ReentrantLock比synchronized高效的原因,缺點(diǎn)是很浪費(fèi)cpu資源。

三、所有線程都執(zhí)行完畢后調(diào)用unlock()方法

unlock()方法是通過AQS的release(int)方法實(shí)現(xiàn)的,我們可以看一下:

public void unlock() {
        sync.release(1);
    }
 
 
public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease()是由子類實(shí)現(xiàn)的,我們來看一下ReentrantLock中的Sync對它的實(shí)現(xiàn):

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

先通過getState獲得狀態(tài)標(biāo)識,如果這個(gè)標(biāo)識和要釋放的數(shù)量相等,就會(huì)把當(dāng)前占有鎖的線程設(shè)置為null,實(shí)現(xiàn)鎖的釋放,然后返回true,否則把狀態(tài)標(biāo)識減去releases再返回false。

以上所述是小編給大家介紹的java并發(fā)之重入鎖-ReentrantLock詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java使用反射獲取字段屬性

    Java使用反射獲取字段屬性

    這篇文章主要為大家詳細(xì)介紹了Java如何利用反射實(shí)現(xiàn)獲取字段屬性值,文中的示例代碼講解詳細(xì),具有很好的參考價(jià)值,希望對大家有所幫助
    2023-06-06
  • SpringBoot通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)及單線程運(yùn)行問題解決

    SpringBoot通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)及單線程運(yùn)行問題解決

    Scheduled定時(shí)任務(wù)是Spring boot自身提供的功能,所以不需要引入Maven依賴包,下面這篇文章主要給大家介紹了關(guān)于SpringBoot通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)以及問題解決的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • mac下idea啟動(dòng)web項(xiàng)目報(bào)錯(cuò)java.net.SocketException:socket closed問題

    mac下idea啟動(dòng)web項(xiàng)目報(bào)錯(cuò)java.net.SocketException:socket closed

    本文主要介紹了作者在項(xiàng)目啟動(dòng)時(shí)遇到的一個(gè)問題——無法打開調(diào)試端口,經(jīng)過一系列排查和嘗試,最終發(fā)現(xiàn)是由于權(quán)限問題導(dǎo)致的,作者還分享了如何修改文件權(quán)限的方法,并提醒大家不要隨意kill掉占用端口的進(jìn)程
    2024-12-12
  • java使用CountDownLatch實(shí)現(xiàn)多線程協(xié)作

    java使用CountDownLatch實(shí)現(xiàn)多線程協(xié)作

    在多線程編程中,經(jīng)常需要實(shí)現(xiàn)一種機(jī)制來協(xié)調(diào)多個(gè)線程的執(zhí)行,以確保某些操作在所有線程完成后再進(jìn)行,CountDownLatch?就是?Java?并發(fā)包中提供的一種同步工具,下面我們就來看看如何使用CountDownLatch實(shí)現(xiàn)多線程協(xié)作吧
    2023-11-11
  • spring中的ObjectPostProcessor詳解

    spring中的ObjectPostProcessor詳解

    這篇文章主要介紹了spring中的ObjectPostProcessor詳解,Spring Security 的 Java 配置不會(huì)公開其配置的每個(gè)對象的每個(gè)屬性,這簡化了大多數(shù)用戶的配置,畢竟,如果每個(gè)屬性都公開,用戶可以使用標(biāo)準(zhǔn) bean 配置,需要的朋友可以參考下
    2024-01-01
  • java逗號分隔String字符串及數(shù)組、集合相互轉(zhuǎn)換

    java逗號分隔String字符串及數(shù)組、集合相互轉(zhuǎn)換

    我們在日常開發(fā)時(shí)會(huì)經(jīng)常遇到將一個(gè)字符串按照逗號進(jìn)行分割,這篇文章主要給大家介紹了關(guān)于java逗號分隔String字符串及數(shù)組、集合相互轉(zhuǎn)換的相關(guān)資料,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2024-02-02
  • SpringBoot利用觀察者模式實(shí)現(xiàn)聯(lián)動(dòng)更新機(jī)制

    SpringBoot利用觀察者模式實(shí)現(xiàn)聯(lián)動(dòng)更新機(jī)制

    觀察者模式(Observer Pattern)是一種軟件設(shè)計(jì)模式,在許多應(yīng)用系統(tǒng)中,我們經(jīng)常需要處理多個(gè)表之間的關(guān)聯(lián)更新問題,本文將通過一個(gè)具體的案例,介紹如何在Spring Boot項(xiàng)目中利用觀察者模式來優(yōu)雅地解決這一需求,需要的朋友可以參考下
    2024-07-07
  • 完整java開發(fā)中JDBC連接數(shù)據(jù)庫代碼和步驟

    完整java開發(fā)中JDBC連接數(shù)據(jù)庫代碼和步驟

    這篇文章主要介紹了完整java開發(fā)中JDBC連接數(shù)據(jù)庫代碼和步驟,需要的朋友可以參考下
    2015-09-09
  • 歸并排序時(shí)間復(fù)雜度過程推導(dǎo)詳解

    歸并排序時(shí)間復(fù)雜度過程推導(dǎo)詳解

    這篇文章主要介紹了C語言實(shí)現(xiàn)排序算法之歸并排序,對歸并排序的原理及實(shí)現(xiàn)過程做了非常詳細(xì)的解讀,需要的朋友可以參考下,希望能幫助到你
    2021-08-08
  • Spring-boot集成pg、mongo多數(shù)據(jù)源過程詳解

    Spring-boot集成pg、mongo多數(shù)據(jù)源過程詳解

    這篇文章主要介紹了Spring-boot集成pg、mongo多數(shù)據(jù)源過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評論

静海县| 灵寿县| 儋州市| 新蔡县| 涟水县| 本溪市| 祁门县| 固镇县| 聂荣县| 黄陵县| 永宁县| 开鲁县| 巧家县| 法库县| 普兰县| 桐城市| 玛多县| 方山县| 抚州市| 读书| 娄烦县| 平谷区| 安仁县| 宣恩县| 成安县| 台江县| 新化县| 张家港市| 建水县| 莱芜市| 托克逊县| 牟定县| 油尖旺区| 乌兰浩特市| 固镇县| 英山县| 台南市| 景泰县| 福安市| 确山县| 胶南市|