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

java高并發(fā)的ReentrantLock重入鎖

 更新時(shí)間:2021年10月27日 11:02:29   作者:路人甲Java  
這篇文章主要介紹了如何教你完全理解ReentrantLock重入鎖,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來一起學(xué)習(xí)一下吧

synchronized的局限性

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

1.當(dāng)線程嘗試獲取鎖的時(shí)候,如果獲取不到鎖會(huì)一直阻塞,這個(gè)阻塞的過程,用戶無法控制

2.如果獲取鎖的線程進(jìn)入休眠或者阻塞,除非當(dāng)前線程異常,否則其他線程嘗試獲取鎖必須一直等待

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

ReentrantLock

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

1.可重入鎖:可重入鎖是指同一個(gè)線程可以多次獲得同一把鎖;ReentrantLock和關(guān)鍵字Synchronized都是可重入鎖

2.可中斷鎖:可中斷鎖時(shí)只線程在獲取鎖的過程中,是否可以相應(yīng)線程中斷操作。synchronized是不可中斷的,ReentrantLock是可中斷的

3.公平鎖和非公平鎖:公平鎖是指多個(gè)線程嘗試獲取同一把鎖的時(shí)候,獲取鎖的順序按照線程到達(dá)的先后順序獲取,而不是隨機(jī)插隊(duì)的方式獲取。synchronized是非公平鎖,而ReentrantLock是兩種都可以實(shí)現(xiàn),不過默認(rèn)是非公平鎖

ReentrantLock基本使用

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

synchronized方式:

package com.itsoku.chat06;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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的使用過程:

1.創(chuàng)建鎖:ReentrantLock lock = new ReentrantLock();

2.獲取鎖:lock.lock()

3.釋放鎖:lock.unlock();

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

ReentrantLock是可重入鎖

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

package com.itsoku.chat06;	
import java.util.concurrent.locks.ReentrantLock;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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)致死鎖,程序是無法正常結(jié)束的。ReentrantLock命名也挺好的Re entrant Lock,和其名字一樣,可重入鎖。

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

1.lock()方法和unlock()方法需要成對(duì)出現(xiàn),鎖了幾次,也要釋放幾次,否則后面的線程無法獲取鎖了;可以將add中的unlock刪除一個(gè)事實(shí),上面代碼運(yùn)行將無法結(jié)束

2.unlock()方法放在finally中執(zhí)行,保證不管程序是否有異常,鎖必定會(huì)釋放

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

在大多數(shù)情況下,鎖的申請(qǐng)都是非公平的,也就是說,線程1首先請(qǐng)求鎖A,接著線程2也請(qǐng)求了鎖A。那么當(dāng)鎖A可用時(shí),是線程1可獲得鎖還是線程2可獲得鎖呢?這是不一定的,系統(tǒng)只是會(huì)從這個(gè)鎖的等待隊(duì)列中隨機(jī)挑選一個(gè),因此不能保證其公平性。這就好比買票不排隊(duì),大家都圍在售票窗口前,售票員忙的焦頭爛額,也顧及不上誰先誰后,隨便找個(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)行開發(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)建的是公平鎖,公平鎖看起來很不錯(cuò),不過要實(shí)現(xiàn)公平鎖,系統(tǒng)內(nèi)部肯定需要維護(hù)一個(gè)有序隊(duì)列,因此公平鎖的實(shí)現(xiàn)成本比較高,性能相對(duì)于非公平鎖來說相對(duì)低一些。因此,在默認(rèn)情況下,鎖是非公平的,如果沒有特別要求,則不建議使用公平鎖。

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

package com.itsoku.chat06;	
import java.util.concurrent.locks.ReentrantLock;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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獲取鎖的過程是可中斷的

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

1.要么獲取到鎖然后繼續(xù)后面的操作

2.要么一直等待,直到其他線程釋放鎖為止

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

示例代碼:

package com.itsoku.chat06;	
import java.util.concurrent.TimeUnit;	
import java.util.concurrent.locks.ReentrantLock;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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)程序無法結(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)象,程序是無法結(jié)束的。

我們隊(duì)上面代碼改造一下,線程t2一直無法獲取到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

640?wx_fmt=png

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)于獲取鎖的過程中被中斷,注意幾點(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)鍵字獲取鎖的過程中,只能等待其他線程把鎖釋放之后才能夠有機(jī)會(huì)獲取到所。所以獲取鎖的時(shí)間有長有短。如果獲取鎖的時(shí)間能夠設(shè)置超時(shí)時(shí)間,那就非常好了。

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

tryLock無參方法

看一下源碼中tryLock方法:

public boolean tryLock()

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

package com.itsoku.chat06;	
import java.util.concurrent.TimeUnit;	
import java.util.concurrent.locks.ReentrantLock;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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() + "開始獲取鎖!");	
                //獲取鎖超時(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開始獲取鎖! 
1563356291081:t2獲取到了鎖! 
1563356291081:t1開始獲取鎖! 
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í)行的過程中,如果調(diào)用了線程的中斷interrupt()方法,會(huì)觸發(fā)InterruptedException異常。

示例:

package com.itsoku.chat06;	
import java.util.concurrent.TimeUnit;	
import java.util.concurrent.locks.ReentrantLock;	
/**	
 * 微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請(qǐng)關(guā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() + "開始獲取鎖!");	
                //獲取鎖超時(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開始獲取鎖! 
1563355512901:t1開始獲取鎖! 
1563355512902:t2獲取到了鎖! 
1563355515904:t1未能獲取到鎖!

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

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

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è)方法的聲明上可以可以看出來

ReentrantLock其他常用的方法

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

獲取鎖的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異常說一下,看到方法聲明上帶有 throwsInterruptedException,表示該方法可以相應(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)線程的中斷

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java19新特性中外部函數(shù)與內(nèi)存API

    Java19新特性中外部函數(shù)與內(nèi)存API

    Java19引入的外部函數(shù)與內(nèi)存API(預(yù)覽功能)是Project Panama一部分,旨在簡(jiǎn)化Java與本地代碼及非堆內(nèi)存的交互,提供更低層次的編程能力,解決了傳統(tǒng)JNI調(diào)用的復(fù)雜性、安全性和性能局限,特別適合高性能計(jì)算和系統(tǒng)編程領(lǐng)域,感興趣的可以了解一下
    2024-09-09
  • Java中解決跨域問題的方法匯總(建議收藏)

    Java中解決跨域問題的方法匯總(建議收藏)

    我們?cè)陂_發(fā)過程中經(jīng)常會(huì)遇到前后端分離而導(dǎo)致的跨域問題,導(dǎo)致無法獲取返回結(jié)果,下面給大家介紹Java中解決跨域問題的方法匯總,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Java源碼解析Integer方法解讀

    Java源碼解析Integer方法解讀

    這篇文章主要介紹了Java源碼解析Integer方法解讀,包括toString方法、toUnsignedString方法、highestOneBit方法等,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • java中BigDecimal的使用踩坑記錄

    java中BigDecimal的使用踩坑記錄

    這篇文章主要為大家詳細(xì)介紹了java中使用BigDecimal會(huì)踩坑的地方以及相關(guān)的解決方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • 精致小巧的java相冊(cè)制作方法

    精致小巧的java相冊(cè)制作方法

    這篇文章主要為大家詳細(xì)介紹了精致小巧的java相冊(cè)制作方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • java的IO流詳細(xì)解讀

    java的IO流詳細(xì)解讀

    這篇文章主要介紹了java的IO流詳細(xì)解讀,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • Java中時(shí)間戳和時(shí)間的轉(zhuǎn)換方法代碼

    Java中時(shí)間戳和時(shí)間的轉(zhuǎn)換方法代碼

    這篇文章主要介紹了Java中時(shí)間戳和時(shí)間的轉(zhuǎn)換的相關(guān)資料,Java8中時(shí)間戳與日期時(shí)間對(duì)象之間的轉(zhuǎn)換是編程中常見的操作,通過時(shí)間字符串獲取時(shí)間對(duì)象也是其中的一種方法,需要的朋友可以參考下
    2025-03-03
  • Mybatis全面分頁插件

    Mybatis全面分頁插件

    這篇文章主要為大家詳細(xì)介紹了Mybatis全面分頁插件的使用方法,比較適用于在分頁時(shí)候進(jìn)行攔截,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Spring Boot+maven打war包的方法

    Spring Boot+maven打war包的方法

    這篇文章主要介紹了Spring Boot+maven打war包的方法,本文通過實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2018-05-05
  • HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)

    HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)

    這篇文章主要介紹了HashMap實(shí)現(xiàn)保存兩個(gè)key相同的數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06

最新評(píng)論

日土县| 内乡县| 北宁市| 平顺县| 涡阳县| 荥经县| 兴城市| 古蔺县| 比如县| 大港区| 固始县| 西乌| 林甸县| 饶平县| 苗栗市| 西宁市| 云安县| 驻马店市| 安顺市| 扎赉特旗| 泽普县| 九龙城区| 长白| 鲁山县| 昌乐县| 应用必备| 玛纳斯县| 新绛县| 黑水县| 招远市| 白沙| 万宁市| 行唐县| 临邑县| 永春县| 新丰县| 肇州县| 天长市| 潞城市| 德钦县| 冀州市|