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

ReentrantLock獲取鎖釋放鎖的流程示例分析

 更新時(shí)間:2022年11月23日 16:40:40   作者:Alan_YYL  
這篇文章主要為大家介紹了ReentrantLock獲取鎖釋放鎖的流程示例分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

目的

  • 了解ReentrantLock獲取鎖、釋放鎖的流程

代碼

package com.company.aqs;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * ReentrantLock使用案例——使用ReentrantLock加鎖
 * @Author: Alan
 * @Date: 2022/11/20 01:38
 */
public class ReentrantLockDemo {
    private static int sum=0;
    private static Lock lock=new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                // 獲取鎖
                lock.lock();
                try {
                    for (int j = 0; j < 1000; j++) {
                        sum++;
                    }
                }finally {
                    // 在finally代碼塊中釋放鎖
                    lock.unlock();
                }
            }).start();
        }
        // 保證所有線(xiàn)程執(zhí)行完畢
        Thread.sleep(1000);
        System.out.println(sum);
    }
}

這是一個(gè)使用ReentrantLock實(shí)現(xiàn)多線(xiàn)程求和的案例。代碼邏輯比較簡(jiǎn)單,外層循環(huán)開(kāi)啟了3個(gè)線(xiàn)程,然后每個(gè)線(xiàn)程內(nèi)多sum累加1000,最后輸出結(jié)果sum=1000。

獲取鎖流程

整個(gè)過(guò)程概括起來(lái)就做了兩件事兒

  • 獲取鎖成功,執(zhí)行當(dāng)前線(xiàn)程內(nèi)的其他事情;
  • 獲取鎖失敗,當(dāng)前線(xiàn)程加入同步隊(duì)列,同時(shí)阻塞當(dāng)前線(xiàn)程。

當(dāng)?shù)谝粋€(gè)線(xiàn)程(thead0)進(jìn)來(lái)的時(shí)候,通過(guò)CAS去修改state屬性為1,如果成功,通過(guò)setExclusiveOwnerThread()方法設(shè)置exclusiveOwnerThread為當(dāng)前線(xiàn)程

此時(shí),第二個(gè)線(xiàn)程(thead1)進(jìn)來(lái),再去通過(guò)CAS修改state屬性為1時(shí),便會(huì)失敗,此時(shí)進(jìn)入acquire()方法。最終會(huì)走到如下方法,首先通過(guò)tryAcquire()方法再次嘗試去獲取鎖。

tryAcquire()方法內(nèi)部還是會(huì)通過(guò)CAS去獲取鎖。此時(shí)鎖資源還被第二線(xiàn)程持有,因此會(huì)返回false?,F(xiàn)在接著看acquire()方法中的if判斷。

此時(shí),會(huì)進(jìn)行acquireQueued(addWaiter(Node.EXCLUSIVE), arg))判斷。這里需要執(zhí)行兩個(gè)方法addWaiter()和acquireQueued()。首先看addWaiter()方法。這個(gè)方法,我們需要關(guān)注以下四點(diǎn)。

  • 首先會(huì)先構(gòu)造一個(gè)node節(jié)點(diǎn)(節(jié)點(diǎn)內(nèi)部細(xì)節(jié),可以看其構(gòu)造方法)。
  • 如果tail(同步隊(duì)列尾節(jié)點(diǎn)指針)不為空,其實(shí)也就是同步隊(duì)列不為空,那么就把第1步構(gòu)建的節(jié)點(diǎn)通過(guò)尾插法加入隊(duì)列中,然后返回

如果同步隊(duì)列為空了,那么執(zhí)行enq()方法,這個(gè)方法為我們做了兩件事兒。

  • 如果同步隊(duì)列為空,那么初始化隊(duì)列
  • 隊(duì)列初始化完成后,將node節(jié)點(diǎn)入隊(duì)。

通過(guò)addWaiter()方法和enq()方法,我們也可以看出來(lái),AQS中的同步隊(duì)列是通過(guò)雙向鏈表來(lái)實(shí)現(xiàn)的,節(jié)點(diǎn)入隊(duì)和出隊(duì),需要修改兩個(gè)指針才行(prev和next)。

addWaiter()方法執(zhí)行執(zhí)行完畢后,我們通過(guò)下面這張圖大致看下此時(shí)同步隊(duì)列中的節(jié)點(diǎn)指向情況。此處,不太理解可以再回頭看看enq()方法的執(zhí)行流程。

addWaiter()方法執(zhí)行執(zhí)行完畢后,會(huì)返回入隊(duì)后的新節(jié)點(diǎn)。然后開(kāi)始執(zhí)行acquireQueued()方法。這個(gè)方法做了五件事兒。

  • 獲取當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)p
  • 如果p是頭節(jié)點(diǎn),那么再次嘗試去獲取鎖,獲取鎖成功,就可以跳出循環(huán)
  • 獲取鎖失敗,通過(guò)shouldParkAfterFailedAcquire()去修改waitSatus為-1(為什么修改為-1,這里可以從AQS的源碼中找到原因,后續(xù)獲取鎖的流程也會(huì)遵從這個(gè)邏輯)

4. parkAndCheckInterrupt()方法會(huì)阻塞當(dāng)前線(xiàn)程,同時(shí),能夠返回當(dāng)前線(xiàn)程的中斷狀態(tài)(Thread.interrupted()會(huì)清除中斷標(biāo)記位)。

經(jīng)過(guò)上述的一通操作,我們可以知道,線(xiàn)程1沒(méi)有獲取到鎖,被加入到了同步隊(duì)列,并且還對(duì)其進(jìn)行了阻塞。概括下就是四個(gè)字“入隊(duì)”、“阻塞”。此時(shí)我們的同步隊(duì)列也變成如下所示。和上述執(zhí)行完addWaiter()方法相比,只是線(xiàn)程1節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn),waitStaus被設(shè)置成了-1。

釋放鎖流程

整個(gè)過(guò)程(只考慮釋放鎖成功)概括起來(lái)做了三件事兒

  • 釋放鎖資源;
  • 喚醒同步隊(duì)列中頭節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的線(xiàn)程
  • 步驟2被喚醒的該線(xiàn)程嘗試競(jìng)爭(zhēng)鎖,競(jìng)爭(zhēng)鎖成功,那么更新同步隊(duì)列(即頭節(jié)點(diǎn)出隊(duì))。

當(dāng)?shù)谝粋€(gè)線(xiàn)程(thread0)執(zhí)行完自己的業(yè)務(wù)流程后,就會(huì)釋放鎖。此時(shí),我們來(lái)看看釋放鎖的流程又是什么樣子的。調(diào)用unlock()方法可以對(duì)鎖進(jìn)行釋放,需要注意的時(shí),為了避免死鎖,需要將該方法的調(diào)用放在fiaally代碼塊中。

當(dāng)thread0去釋放鎖時(shí),會(huì)調(diào)用release()方法,該方法主要做了兩件事兒。

  • 調(diào)用tryRelease()方法釋放鎖

其方法內(nèi)部,會(huì)將state設(shè)置為0,同時(shí)通過(guò)setExclusiveOwnerThread()方法設(shè)置exclusiveOwnerThread為當(dāng)null,代表此時(shí)鎖資源被釋放,沒(méi)有任何線(xiàn)程持有鎖資源

如果第一步返回true,即釋放鎖成功,那么開(kāi)始第二步。第二步首先獲取同步隊(duì)列的頭節(jié)點(diǎn),查看其waitStatus屬性。這里我們把剛才獲取鎖過(guò)后,同步隊(duì)列中的節(jié)點(diǎn)情況再放一下。此時(shí),我們的head節(jié)點(diǎn)的waitStatus為-1,因此會(huì)進(jìn)入unparkSuccessor()方法

unparkSuccessor()方法,主要做了以下三件事兒。注意第三步,根據(jù)我們當(dāng)前同步隊(duì)列的情況來(lái)看,LockSupport.unpark()方法會(huì)喚醒線(xiàn)程1。

當(dāng)執(zhí)行完unparkSuccessor()方法中的LockSupport.unpark()方法后,線(xiàn)程1(thread1)就會(huì)被喚醒了。線(xiàn)程1被喚醒過(guò)后,我們又來(lái)看看線(xiàn)程1的執(zhí)行情況。此時(shí)線(xiàn)程1,會(huì)繼續(xù)執(zhí)行acquireQueued()方法中的for循環(huán)(注意:這是一個(gè)死循環(huán)哦)。執(zhí)行順序和獲取鎖時(shí)是一致的,和獲取鎖有所不同的時(shí),此時(shí)執(zhí)行第2步獲取鎖是會(huì)成功的(因?yàn)閠hread0已經(jīng)釋放鎖了)。

獲取鎖成功后呢,會(huì)讓當(dāng)前同步隊(duì)列中的頭節(jié)點(diǎn)出隊(duì),此時(shí),同步隊(duì)列中的節(jié)點(diǎn)情況如下所示。

此時(shí),釋放鎖的邏輯就執(zhí)行完成了。歸納起來(lái)其實(shí)也很簡(jiǎn)單,首先釋放鎖資源,然后再喚醒同步隊(duì)列中頭節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)對(duì)應(yīng)的線(xiàn)程,最后,更新同步隊(duì)列(出隊(duì))。

總結(jié)

以上便是ReentrantLock獲取鎖、釋放鎖的的大致流程。通過(guò)這篇文章,讀者對(duì)ReentrantLock的獲取鎖、釋放鎖過(guò)程有一個(gè)大致的了解了,細(xì)心的讀者可能會(huì)發(fā)現(xiàn),獲取鎖時(shí)acquireQueued()方法中有一個(gè)隊(duì)cancelAcquire()方法的調(diào)用邏輯,這里沒(méi)有詳細(xì)解釋?zhuān)┲鲿?huì)在后面的文章中詳細(xì)來(lái)解釋這個(gè)方法的處理邏輯(flag先立下?。。。?。

以上就是ReentrantLock獲取鎖釋放鎖的流程示例分析的詳細(xì)內(nèi)容,更多關(guān)于ReentrantLock獲取鎖釋放鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中串行流和并行流區(qū)別小結(jié)

    java中串行流和并行流區(qū)別小結(jié)

    串行流和并行流是兩種處理流操作的方式,串行流適用于小數(shù)據(jù)量且簡(jiǎn)單的數(shù)據(jù)處理,并行流則適用于大規(guī)模數(shù)據(jù)處理和需要并行計(jì)算的場(chǎng)景,能夠利用多線(xiàn)程并行處理,選擇使用哪種流取決于數(shù)據(jù)量大小、處理復(fù)雜度和是否需要并行計(jì)算,下面就來(lái)具體介紹一下兩者的區(qū)別
    2024-09-09
  • JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié)

    JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié)

    本篇文章主要介紹了JAVA中的靜態(tài)代理、動(dòng)態(tài)代理以及CGLIB動(dòng)態(tài)代理總結(jié),具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程

    SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程

    這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之易寶支付的流程,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 深度解析Java中的ReentrantLock原理

    深度解析Java中的ReentrantLock原理

    這篇文章主要介紹了關(guān)于ReentrantLock的原理解析,文章通過(guò)代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-07-07
  • Java經(jīng)典算法匯總之冒泡排序

    Java經(jīng)典算法匯總之冒泡排序

    冒泡排序基本思想:在要排序的一組數(shù)中,對(duì)當(dāng)前還未排好序的范圍內(nèi)的全部數(shù),自上而下對(duì)相鄰的兩個(gè)數(shù)依次進(jìn)行比較和調(diào)整,讓較大的數(shù)往下沉,較小的往上冒。即:每當(dāng)兩相鄰的數(shù)比較后發(fā)現(xiàn)它們的排序與排序要求相反時(shí),就將它們互換。
    2016-04-04
  • Java設(shè)計(jì)模式之工廠模式案例詳解

    Java設(shè)計(jì)模式之工廠模式案例詳解

    工廠模式(Factory Pattern)是Java中最常用的設(shè)計(jì)模式之一。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。本文將通過(guò)案例詳細(xì)講解一下工廠模式,需要的可以參考一下
    2022-02-02
  • 用JAVA實(shí)現(xiàn)楊輝三角實(shí)例

    用JAVA實(shí)現(xiàn)楊輝三角實(shí)例

    大家好,本篇文章主要講的是用JAVA實(shí)現(xiàn)楊輝三角實(shí)例,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下
    2022-01-01
  • java計(jì)算集合對(duì)稱(chēng)差的示例代碼

    java計(jì)算集合對(duì)稱(chēng)差的示例代碼

    本篇文章主要介紹了java計(jì)算集合對(duì)稱(chēng)差的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • Java數(shù)據(jù)結(jié)構(gòu)之堆(優(yōu)先隊(duì)列)的實(shí)現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)之堆(優(yōu)先隊(duì)列)的實(shí)現(xiàn)

    堆(優(yōu)先隊(duì)列)是一種典型的數(shù)據(jù)結(jié)構(gòu),其形狀是一棵完全二叉樹(shù),一般用于求解topk問(wèn)題。本文將利用Java語(yǔ)言實(shí)現(xiàn)堆,感興趣的可以學(xué)習(xí)一下
    2022-05-05
  • java this 用法詳解及簡(jiǎn)單實(shí)例

    java this 用法詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了java this 用法詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

当涂县| 阿克苏市| 威海市| 顺义区| 巨野县| 渝中区| 营口市| 友谊县| 赣榆县| 满洲里市| 高州市| 临桂县| 南安市| 清新县| 习水县| 新竹县| 高阳县| 寿阳县| 阿拉尔市| 舒兰市| 特克斯县| 禄劝| 临潭县| 类乌齐县| 巨鹿县| 铜梁县| 阳朔县| 神池县| 云阳县| 长宁区| 西安市| 临高县| 葫芦岛市| 祁连县| 庐江县| 东乌珠穆沁旗| 莱阳市| 杂多县| 文成县| 蒙山县| 新营市|