溫馨提示×

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

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

java高并發(fā)系列 - 第12天JUC:ReentrantLock重入鎖

發(fā)布時(shí)間:2020-06-24 20:34:46 來(lái)源:網(wǎng)絡(luò) 閱讀:201 作者:路人甲Java 欄目:編程語(yǔ)言

java高并發(fā)系列 - 第12天JUC:ReentrantLock重入鎖

本篇文章開(kāi)始將juc中常用的一些類,估計(jì)會(huì)有十來(lái)篇。

synchronized的局限性

synchronized是java內(nèi)置的關(guān)鍵字,它提供了一種獨(dú)占的加鎖方式。synchronized的獲取和釋放鎖由jvm實(shí)現(xiàn),用戶不需要顯示的釋放鎖,非常方便,然而synchronized也有一定的局限性,例如:

  1. 當(dāng)線程嘗試獲取鎖的時(shí)候,如果獲取不到鎖會(huì)一直阻塞,這個(gè)阻塞的過(guò)程,用戶無(wú)法控制
  2. 如果獲取鎖的線程進(jìn)入休眠或者阻塞,除非當(dāng)前線程異常,否則其他線程嘗試獲取鎖必須一直等待

JDK1.5之后發(fā)布,加入了Doug Lea實(shí)現(xiàn)的java.util.concurrent包。包內(nèi)提供了Lock類,用來(lái)提供更多擴(kuò)展的加鎖功能。Lock彌補(bǔ)了synchronized的局限,提供了更加細(xì)粒度的加鎖功能。

ReentrantLock

ReentrantLock是Lock的默認(rèn)實(shí)現(xiàn),在聊ReentranLock之前,我們需要先弄清楚一些概念:

  1. 可重入鎖:可重入鎖是指同一個(gè)線程可以多次獲得同一把鎖;ReentrantLock和關(guān)鍵字Synchronized都是可重入鎖
  2. 可中斷鎖:可中斷鎖時(shí)只線程在獲取鎖的過(guò)程中,是否可以相應(yīng)線程中斷操作。synchronized是不可中斷的,ReentrantLock是可中斷的
  3. 公平鎖和非公平鎖:公平鎖是指多個(gè)線程嘗試獲取同一把鎖的時(shí)候,獲取鎖的順序按照線程到達(dá)的先后順序獲取,而不是隨機(jī)插隊(duì)的方式獲取。synchronized是非公平鎖,而ReentrantLock是兩種都可以實(shí)現(xiàn),不過(guò)默認(rèn)是非公平鎖

ReentrantLock基本使用

我們使用3個(gè)線程來(lái)對(duì)一個(gè)共享變量++操作,先使用synchronized實(shí)現(xiàn),然后使用ReentrantLock實(shí)現(xiàn)。

synchronized方式

package com.itsoku.chat06;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo2 {

    private static int num = 0;

    private static synchronized void add() {
        num++;
    }

    public static class T extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                Demo2.add();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        T t2 = new T();
        T t3 = new T();

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

        System.out.println(Demo2.num);
    }
}

ReentrantLock方式:

package com.itsoku.chat06;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo3 {

    private static int num = 0;

    private static ReentrantLock lock = new ReentrantLock();

    private static void add() {
        lock.lock();
        try {
            num++;
        } finally {
            lock.unlock();
        }

    }

    public static class T extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                Demo3.add();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        T t2 = new T();
        T t3 = new T();

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

        System.out.println(Demo3.num);
    }
}

ReentrantLock的使用過(guò)程:

  1. 創(chuàng)建鎖:ReentrantLock lock = new ReentrantLock();
  2. 獲取鎖:lock.lock()
  3. 釋放鎖:lock.unlock();

對(duì)比上面的代碼,與關(guān)鍵字synchronized相比,ReentrantLock鎖有明顯的操作過(guò)程,開(kāi)發(fā)人員必須手動(dòng)的指定何時(shí)加鎖,何時(shí)釋放鎖,正是因?yàn)檫@樣手動(dòng)控制,ReentrantLock對(duì)邏輯控制的靈活度要遠(yuǎn)遠(yuǎn)勝于關(guān)鍵字synchronized,上面代碼需要注意lock.unlock()一定要放在finally中,否則,若程序出現(xiàn)了異常,鎖沒(méi)有釋放,那么其他線程就再也沒(méi)有機(jī)會(huì)獲取這個(gè)鎖了。

ReentrantLock是可重入鎖

來(lái)驗(yàn)證一下ReentrantLock是可重入鎖,實(shí)例代碼:

package com.itsoku.chat06;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo4 {
    private static int num = 0;
    private static ReentrantLock lock = new ReentrantLock();

    private static void add() {
        lock.lock();
        lock.lock();
        try {
            num++;
        } finally {
            lock.unlock();
            lock.unlock();
        }
    }

    public static class T extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                Demo4.add();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        T t2 = new T();
        T t3 = new T();

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

        System.out.println(Demo4.num);
    }
}

上面代碼中add()方法中,當(dāng)一個(gè)線程進(jìn)入的時(shí)候,會(huì)執(zhí)行2次獲取鎖的操作,運(yùn)行程序可以正常結(jié)束,并輸出和期望值一樣的30000,假如ReentrantLock是不可重入的鎖,那么同一個(gè)線程第2次獲取鎖的時(shí)候由于前面的鎖還未釋放而導(dǎo)致死鎖,程序是無(wú)法正常結(jié)束的。ReentrantLock命名也挺好的Re entrant Lock,和其名字一樣,可重入鎖。

代碼中還有幾點(diǎn)需要注意:

  1. lock()方法和unlock()方法需要成對(duì)出現(xiàn),鎖了幾次,也要釋放幾次,否則后面的線程無(wú)法獲取鎖了;可以將add中的unlock刪除一個(gè)事實(shí),上面代碼運(yùn)行將無(wú)法結(jié)束
  2. unlock()方法放在finally中執(zhí)行,保證不管程序是否有異常,鎖必定會(huì)釋放

ReentrantLock實(shí)現(xiàn)公平鎖

在大多數(shù)情況下,鎖的申請(qǐng)都是非公平的,也就是說(shuō),線程1首先請(qǐng)求鎖A,接著線程2也請(qǐng)求了鎖A。那么當(dāng)鎖A可用時(shí),是線程1可獲得鎖還是線程2可獲得鎖呢?這是不一定的,系統(tǒng)只是會(huì)從這個(gè)鎖的等待隊(duì)列中隨機(jī)挑選一個(gè),因此不能保證其公平性。這就好比買票不排隊(duì),大家都圍在售票窗口前,售票員忙的焦頭爛額,也顧及不上誰(shuí)先誰(shuí)后,隨便找個(gè)人出票就完事了,最終導(dǎo)致的結(jié)果是,有些人可能一直買不到票。而公平鎖,則不是這樣,它會(huì)按照到達(dá)的先后順序獲得資源。公平鎖的一大特點(diǎn)是:它不會(huì)產(chǎn)生饑餓現(xiàn)象,只要你排隊(duì),最終還是可以等到資源的;synchronized關(guān)鍵字默認(rèn)是有jvm內(nèi)部實(shí)現(xiàn)控制的,是非公平鎖。而ReentrantLock運(yùn)行開(kāi)發(fā)者自己設(shè)置鎖的公平性。

看一下jdk中ReentrantLock的源碼,2個(gè)構(gòu)造方法:

public ReentrantLock() {
    sync = new NonfairSync();
}

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

默認(rèn)構(gòu)造方法創(chuàng)建的是非公平鎖。

第2個(gè)構(gòu)造方法,有個(gè)fair參數(shù),當(dāng)fair為true的時(shí)候創(chuàng)建的是公平鎖,公平鎖看起來(lái)很不錯(cuò),不過(guò)要實(shí)現(xiàn)公平鎖,系統(tǒng)內(nèi)部肯定需要維護(hù)一個(gè)有序隊(duì)列,因此公平鎖的實(shí)現(xiàn)成本比較高,性能相對(duì)于非公平鎖來(lái)說(shuō)相對(duì)低一些。因此,在默認(rèn)情況下,鎖是非公平的,如果沒(méi)有特別要求,則不建議使用公平鎖。

公平鎖和非公平鎖在程序調(diào)度上是很不一樣,來(lái)一個(gè)公平鎖示例看一下:

package com.itsoku.chat06;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo5 {
    private static int num = 0;
    private static ReentrantLock fairLock = new ReentrantLock(true);

    public static class T extends Thread {
        public T(String name) {
            super(name);
        }

        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                fairLock.lock();
                try {
                    System.out.println(this.getName() + "獲得鎖!");
                } finally {
                    fairLock.unlock();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T("t1");
        T t2 = new T("t2");
        T t3 = new T("t3");

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();
    }
}

運(yùn)行結(jié)果輸出:

t1獲得鎖!
t2獲得鎖!
t3獲得鎖!
t1獲得鎖!
t2獲得鎖!
t3獲得鎖!
t1獲得鎖!
t2獲得鎖!
t3獲得鎖!
t1獲得鎖!
t2獲得鎖!
t3獲得鎖!
t1獲得鎖!
t2獲得鎖!
t3獲得鎖!

看一下輸出的結(jié)果,鎖時(shí)按照先后順序獲得的。

修改一下上面代碼,改為非公平鎖試試,如下:

ReentrantLock fairLock = new ReentrantLock(false);

運(yùn)行結(jié)果如下:

t1獲得鎖!
t3獲得鎖!
t3獲得鎖!
t3獲得鎖!
t3獲得鎖!
t1獲得鎖!
t1獲得鎖!
t1獲得鎖!
t1獲得鎖!
t2獲得鎖!
t2獲得鎖!
t2獲得鎖!
t2獲得鎖!
t2獲得鎖!
t3獲得鎖!

可以看到t3可能會(huì)連續(xù)獲得鎖,結(jié)果是比較隨機(jī)的,不公平的。

ReentrantLock獲取鎖的過(guò)程是可中斷的

對(duì)于synchronized關(guān)鍵字,如果一個(gè)線程在等待獲取鎖,最終只有2種結(jié)果:

  1. 要么獲取到鎖然后繼續(xù)后面的操作
  2. 要么一直等待,直到其他線程釋放鎖為止

而ReentrantLock提供了另外一種可能,就是在等的獲取鎖的過(guò)程中(發(fā)起獲取鎖請(qǐng)求到還未獲取到鎖這段時(shí)間內(nèi))是可以被中斷的,也就是說(shuō)在等待鎖的過(guò)程中,程序可以根據(jù)需要取消獲取鎖的請(qǐng)求。有些使用這個(gè)操作是非常有必要的。比如:你和好朋友越好一起去打球,如果你等了半小時(shí)朋友還沒(méi)到,突然你接到一個(gè)電話,朋友由于突發(fā)狀況,不能來(lái)了,那么你一定達(dá)到回府。中斷操作正是提供了一套類似的機(jī)制,如果一個(gè)線程正在等待獲取鎖,那么它依然可以收到一個(gè)通知,被告知無(wú)需等待,可以停止工作了。

示例代碼:

package com.itsoku.chat06;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo6 {
    private static ReentrantLock lock1 = new ReentrantLock(false);
    private static ReentrantLock lock2 = new ReentrantLock(false);

    public static class T extends Thread {
        int lock;

        public T(String name, int lock) {
            super(name);
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                if (this.lock == 1) {
                    lock1.lockInterruptibly();
                    TimeUnit.SECONDS.sleep(1);
                    lock2.lockInterruptibly();
                } else {
                    lock2.lockInterruptibly();
                    TimeUnit.SECONDS.sleep(1);
                    lock1.lockInterruptibly();
                }
            } catch (InterruptedException e) {
                System.out.println("中斷標(biāo)志:" + this.isInterrupted());
                e.printStackTrace();
            } finally {
                if (lock1.isHeldByCurrentThread()) {
                    lock1.unlock();
                }
                if (lock2.isHeldByCurrentThread()) {
                    lock2.unlock();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T("t1", 1);
        T t2 = new T("t2", 2);

        t1.start();
        t2.start();
    }
}

先運(yùn)行一下上面代碼,發(fā)現(xiàn)程序無(wú)法結(jié)束,使用jstack查看線程堆棧信息,發(fā)現(xiàn)2個(gè)線程死鎖了。

Found one Java-level deadlock:
=============================
"t2":
  waiting for ownable synchronizer 0x0000000717380c20, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "t1"
"t1":
  waiting for ownable synchronizer 0x0000000717380c50, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "t2"

lock1被線程t1占用,lock2倍線程t2占用,線程t1在等待獲取lock2,線程t2在等待獲取lock1,都在相互等待獲取對(duì)方持有的鎖,最終產(chǎn)生了死鎖,如果是在synchronized關(guān)鍵字情況下發(fā)生了死鎖現(xiàn)象,程序是無(wú)法結(jié)束的。

我們隊(duì)上面代碼改造一下,線程t2一直無(wú)法獲取到lock1,那么等待5秒之后,我們中斷獲取鎖的操作。主要修改一下main方法,如下:

T t1 = new T("t1", 1);
T t2 = new T("t2", 2);

t1.start();
t2.start();

TimeUnit.SECONDS.sleep(5);
t2.interrupt();

新增了2行代碼TimeUnit.SECONDS.sleep(5);t2.interrupt();,程序可以結(jié)束了,運(yùn)行結(jié)果:

java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at com.itsoku.chat06.Demo6$T.run(Demo6.java:31)
中斷標(biāo)志:false

從上面信息中可以看出,代碼的31行觸發(fā)了異常,中斷標(biāo)志輸出:false

java高并發(fā)系列 - 第12天JUC:ReentrantLock重入鎖

t2在31行一直獲取不到lock1的鎖,主線程中等待了5秒之后,t2線程調(diào)用了interrupt()方法,將線程的中斷標(biāo)志置為true,此時(shí)31行會(huì)觸發(fā)InterruptedException異常,然后線程t2可以繼續(xù)向下執(zhí)行,釋放了lock2的鎖,然后線程t1可以正常獲取鎖,程序得以繼續(xù)進(jìn)行。線程發(fā)送中斷信號(hào)觸發(fā)InterruptedException異常之后,中斷標(biāo)志將被清空。

關(guān)于獲取鎖的過(guò)程中被中斷,注意幾點(diǎn):

  1. ReentrankLock中必須使用實(shí)例方法lockInterruptibly()獲取鎖時(shí),在線程調(diào)用interrupt()方法之后,才會(huì)引發(fā)InterruptedException異常
  2. 線程調(diào)用interrupt()之后,線程的中斷標(biāo)志會(huì)被置為true
  3. 觸發(fā)InterruptedException異常之后,線程的中斷標(biāo)志有會(huì)被清空,即置為false
  4. 所以當(dāng)線程調(diào)用interrupt()引發(fā)InterruptedException異常,中斷標(biāo)志的變化是:false->true->false

ReentrantLock鎖申請(qǐng)等待限時(shí)

申請(qǐng)鎖等待限時(shí)是什么意思?一般情況下,獲取鎖的時(shí)間我們是不知道的,synchronized關(guān)鍵字獲取鎖的過(guò)程中,只能等待其他線程把鎖釋放之后才能夠有機(jī)會(huì)獲取到所。所以獲取鎖的時(shí)間有長(zhǎng)有短。如果獲取鎖的時(shí)間能夠設(shè)置超時(shí)時(shí)間,那就非常好了。

ReentrantLock剛好提供了這樣功能,給我們提供了獲取鎖限時(shí)等待的方法tryLock(),可以選擇傳入時(shí)間參數(shù),表示等待指定的時(shí)間,無(wú)參則表示立即返回鎖申請(qǐng)的結(jié)果:true表示獲取鎖成功,false表示獲取鎖失敗。

tryLock無(wú)參方法

看一下源碼中tryLock方法:

public boolean tryLock()

返回boolean類型的值,此方法會(huì)立即返回,結(jié)果表示獲取鎖是否成功,示例:

package com.itsoku.chat06;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo8 {
    private static ReentrantLock lock1 = new ReentrantLock(false);

    public static class T extends Thread {

        public T(String name) {
            super(name);
        }

        @Override
        public void run() {
            try {
                System.out.println(System.currentTimeMillis() + ":" + this.getName() + "開(kāi)始獲取鎖!");
                //獲取鎖超時(shí)時(shí)間設(shè)置為3秒,3秒內(nèi)是否能否獲取鎖都會(huì)返回
                if (lock1.tryLock()) {
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "獲取到了鎖!");
                    //獲取到鎖之后,休眠5秒
                    TimeUnit.SECONDS.sleep(5);
                } else {
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "未能獲取到鎖!");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (lock1.isHeldByCurrentThread()) {
                    lock1.unlock();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T("t1");
        T t2 = new T("t2");

        t1.start();
        t2.start();
    }
}

代碼中獲取鎖成功之后,休眠5秒,會(huì)導(dǎo)致另外一個(gè)線程獲取鎖失敗,運(yùn)行代碼,輸出:

1563356291081:t2開(kāi)始獲取鎖!
1563356291081:t2獲取到了鎖!
1563356291081:t1開(kāi)始獲取鎖!
1563356291081:t1未能獲取到鎖!

可以看到t2獲取成功,t1獲取失敗了,tryLock()是立即響應(yīng)的,中間不會(huì)有阻塞。

tryLock有參方法

可以明確設(shè)置獲取鎖的超時(shí)時(shí)間,該方法簽名:

public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException

該方法在指定的時(shí)間內(nèi)不管是否可以獲取鎖,都會(huì)返回結(jié)果,返回true,表示獲取鎖成功,返回false表示獲取失敗。此方法由2個(gè)參數(shù),第一個(gè)參數(shù)是時(shí)間類型,是一個(gè)枚舉,可以表示時(shí)、分、秒、毫秒等待,使用比較方便,第1個(gè)參數(shù)表示在時(shí)間類型上的時(shí)間長(zhǎng)短。此方法在執(zhí)行的過(guò)程中,如果調(diào)用了線程的中斷interrupt()方法,會(huì)觸發(fā)InterruptedException異常。

示例:

package com.itsoku.chat06;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 微信公眾號(hào):javacode2018,獲取年薪50萬(wàn)課程
 */
public class Demo7 {
    private static ReentrantLock lock1 = new ReentrantLock(false);

    public static class T extends Thread {

        public T(String name) {
            super(name);
        }

        @Override
        public void run() {
            try {
                System.out.println(System.currentTimeMillis() + ":" + this.getName() + "開(kāi)始獲取鎖!");
                //獲取鎖超時(shí)時(shí)間設(shè)置為3秒,3秒內(nèi)是否能否獲取鎖都會(huì)返回
                if (lock1.tryLock(3, TimeUnit.SECONDS)) {
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "獲取到了鎖!");
                    //獲取到鎖之后,休眠5秒
                    TimeUnit.SECONDS.sleep(5);
                } else {
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "未能獲取到鎖!");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (lock1.isHeldByCurrentThread()) {
                    lock1.unlock();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        T t1 = new T("t1");
        T t2 = new T("t2");

        t1.start();
        t2.start();
    }
}

程序中調(diào)用了ReentrantLock的實(shí)例方法tryLock(3, TimeUnit.SECONDS),表示獲取鎖的超時(shí)時(shí)間是3秒,3秒后不管是否能否獲取鎖,該方法都會(huì)有返回值,獲取到鎖之后,內(nèi)部休眠了5秒,會(huì)導(dǎo)致另外一個(gè)線程獲取鎖失敗。

運(yùn)行程序,輸出:

1563355512901:t2開(kāi)始獲取鎖!
1563355512901:t1開(kāi)始獲取鎖!
1563355512902:t2獲取到了鎖!
1563355515904:t1未能獲取到鎖!

輸出結(jié)果中分析,t2獲取到鎖了,然后休眠了5秒,t1獲取鎖失敗,t1打印了2條信息,時(shí)間相差3秒左右。

關(guān)于tryLock()方法和tryLock(long timeout, TimeUnit unit)方法,說(shuō)明一下:

  1. 都會(huì)返回boolean值,結(jié)果表示獲取鎖是否成功
  2. tryLock()方法,不管是否獲取成功,都會(huì)立即返回;而有參的tryLock方法會(huì)嘗試在指定的時(shí)間內(nèi)去獲取鎖,中間會(huì)阻塞的現(xiàn)象,在指定的時(shí)間之后會(huì)不管是否能夠獲取鎖都會(huì)返回結(jié)果
  3. tryLock()方法不會(huì)響應(yīng)線程的中斷方法;而有參的tryLock方法會(huì)響應(yīng)線程的中斷方法,而出發(fā)InterruptedException異常,這個(gè)從2個(gè)方法的聲明上可以可以看出來(lái)

ReentrantLock其他常用的方法

  1. isHeldByCurrentThread:實(shí)例方法,判斷當(dāng)前線程是否持有ReentrantLock的鎖,上面代碼中有使用過(guò)。

獲取鎖的4中方法對(duì)比

獲取鎖的方法 是否立即響應(yīng)(不會(huì)阻塞) 是否響應(yīng)中斷
lock() × ×
lockInterruptibly() ×
tryLock() ×
tryLock(long timeout, TimeUnit unit) ×

總結(jié)

  1. ReentrantLock可以實(shí)現(xiàn)公平鎖和非公平鎖
  2. ReentrantLock默認(rèn)實(shí)現(xiàn)的是非公平鎖
  3. ReentrantLock的獲取鎖和釋放鎖必須成對(duì)出現(xiàn),鎖了幾次,也要釋放幾次
  4. 釋放鎖的操作必須放在finally中執(zhí)行
  5. lockInterruptibly()實(shí)例方法可以相應(yīng)線程的中斷方法,調(diào)用線程的interrupt()方法時(shí),lockInterruptibly()方法會(huì)觸發(fā)InterruptedException異常
  6. 關(guān)于InterruptedException異常說(shuō)一下,看到方法聲明上帶有 throws InterruptedException,表示該方法可以相應(yīng)線程中斷,調(diào)用線程的interrupt()方法時(shí),這些方法會(huì)觸發(fā)InterruptedException異常,觸發(fā)InterruptedException時(shí),線程的中斷中斷狀態(tài)會(huì)被清除。所以如果程序由于調(diào)用interrupt()方法而觸發(fā)InterruptedException異常,線程的標(biāo)志由默認(rèn)的false變?yōu)閠ure,然后又變?yōu)閒alse
  7. 實(shí)例方法tryLock()獲會(huì)嘗試獲取鎖,會(huì)立即返回,返回值表示是否獲取成功
  8. 實(shí)例方法tryLock(long timeout, TimeUnit unit)會(huì)在指定的時(shí)間內(nèi)嘗試獲取鎖,指定的時(shí)間內(nèi)是否能夠獲取鎖,都會(huì)返回,返回值表示是否獲取鎖成功,該方法會(huì)響應(yīng)線程的中斷

java高并發(fā)系列連載中,總計(jì)估計(jì)會(huì)有四五十篇文章,可以關(guān)注公眾號(hào):javacode2018,獲取最新文章。

java高并發(fā)系列 - 第12天JUC:ReentrantLock重入鎖

向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