溫馨提示×

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

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

ReentrantLock是什么意思

發(fā)布時(shí)間:2021-06-18 16:48:38 來(lái)源:億速云 閱讀:177 作者:chen 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“ReentrantLock是什么意思”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、前言

在Java 5.0之前,在協(xié)調(diào)對(duì)共享對(duì)象的訪問(wèn)的時(shí)可以使用的機(jī)制只有synchronized 和 volatile。Java 5.0  增加了一種新的機(jī)制:ReentrantLock 。與之前提到過(guò)的機(jī)制相反,ReentrantLock  并不是一種替代內(nèi)置加鎖的方法,而是當(dāng)內(nèi)置解鎖機(jī)制不適用時(shí),作為一種可選擇的高級(jí)功能。

二、簡(jiǎn)介

ReentrantLock 重入鎖實(shí)現(xiàn)了 Lock和 java.io.Serializable接口,并提供了與  synchronized相同的互斥性和內(nèi)存可見(jiàn)性,ReentrantLock  提供了可重入的加鎖語(yǔ)義,能夠?qū)蚕碣Y源能夠重復(fù)加鎖,即當(dāng)前線程獲取該鎖再次獲取不會(huì)被阻塞,并且與synchronized相比,它還為處理鎖的不可用性提供了更高的靈活性,與此同時(shí),ReentrantLock  還支持公平鎖和非公平鎖兩種方式。

ReentrantLock類層次結(jié)構(gòu):

ReentrantLock是什么意思

   ReentrantLock實(shí)現(xiàn)了 Lock和 Serializable接口,內(nèi)部有三個(gè)內(nèi)部類, Sync、 NonfairSync、FairSync      Sync是一個(gè)抽象類型,它繼承AbstractQueuedSynchronizer,這個(gè)AbstractQueuedSynchronizer 是一個(gè)模板類,它實(shí)現(xiàn)了許多和鎖相關(guān)的功能,并提供了鉤子方法供用戶實(shí)現(xiàn),比如tryAcquire、tryRele ase等Sync實(shí)現(xiàn)了AbstractQueuedSynchronizer的 tryRelease方法。      NonfairSync和FairSync兩個(gè)類繼承自Sync,實(shí)現(xiàn)了lock方法,然后分別公平搶占 和非公平搶占針對(duì)tryAcquire有不同的實(shí)現(xiàn)。

三、可重入性

可重入鎖,也叫做  遞歸鎖,從名字上理解,字面意思就是再進(jìn)入的鎖,重入性是指任意線程在獲取到鎖之后能夠再次獲取該鎖而不會(huì)被鎖阻塞,首先他需要具備兩個(gè)條件:1)  線程再次獲取鎖:所需要去識(shí)別獲取鎖的線程是否為當(dāng)前占據(jù)鎖的線程,如果是,則再次獲取成功 2)  鎖的最終釋放:線程重復(fù)n次獲取了鎖,隨后在第n次釋放該鎖后,其它線程能夠獲取到該鎖。鎖的最終釋放要求鎖對(duì)于獲取進(jìn)行計(jì)數(shù)自增,計(jì)數(shù)表示當(dāng)前線程被重復(fù)獲取的次數(shù),而被釋放時(shí),計(jì)數(shù)自減,當(dāng)計(jì)數(shù)為0時(shí)表示鎖已經(jīng)成功釋放。

3.1 鎖的實(shí)現(xiàn)

使用ReentrantLock 案例:

Lock lock = new ReentrantLock();         lock.lock();        try{            //更新對(duì)象狀態(tài)            //捕獲異常,并在必須時(shí)恢復(fù)不變性條件         }catch (Exception e){            e.printStackTrace();        } finally {            lock.unlock();        }

上述代碼中是使用Lock接口的標(biāo)準(zhǔn)使用方式,這種形式比使用內(nèi)置鎖(synchronized )復(fù)雜一些,必須要在 finally  塊中釋放鎖,否則,如果在被保護(hù)的代碼中拋出了異常,那么這個(gè)鎖永遠(yuǎn)都無(wú)法釋放。

四、ReentrantLock 源碼分析

在簡(jiǎn)介中我們知道 ReentrantLock繼承自 Lock接口,  Lock提供了一些獲取鎖和釋放鎖的方法,以及條件判斷的獲取的方法,通過(guò)實(shí)現(xiàn)它來(lái)進(jìn)行鎖的控制,因?yàn)樗秋@示鎖,所以需要顯示指定起始位置和終止位置,下面就來(lái)介紹一下  Lock接口的方法介紹:

ReentrantLock是什么意思

ReentrantLock 也實(shí)現(xiàn)了上面接口的內(nèi)容,同時(shí) ReentrantLock 提供了 公平鎖和  非公平鎖兩種模式,如果沒(méi)有特別的去指定使用何種方式,那么 ReentrantLock 會(huì)默認(rèn)為 非公平鎖,首先我們來(lái)看一下 ReentrantLock  的構(gòu)造函數(shù):

/**      * 無(wú)參的構(gòu)造函數(shù)      */   public ReentrantLock() {         sync = new NonfairSync();     }      /**      * 有參構(gòu)造函數(shù)      * 參數(shù)為布爾類型      */     public ReentrantLock(boolean fair) {         sync = fair ? new FairSync() : new NonfairSync();     }

從上述源碼中我們可以看到:

ReentrantLock  優(yōu)先使用的是無(wú)參構(gòu)造函數(shù),也就是非公平鎖,但是當(dāng)我們調(diào)用有參構(gòu)造函數(shù)時(shí),可以指定使用哪種鎖來(lái)進(jìn)行操作(公平鎖還是非公平鎖),參數(shù)為布爾類型,如果指定為  false 的話代表 非公平鎖 ,如果指定為 true 的話代表的是 公平鎖

Sync 類 是 ReentrantLock 自定義的同步組件,它是 ReentrantLock  里面的一個(gè)內(nèi)部類,它繼承自AQS(AbstractQueuedSynchronizer),Sync 有兩個(gè)子類:公平鎖 FairSync 和 非公平鎖  NonfairSync

ReentrantLock 的獲取與釋放鎖操作都是委托給該同步組件來(lái)實(shí)現(xiàn)的。下面我們來(lái)看一看非公平鎖的 lock() 方法:

4.1 非公平鎖 NonfairSync.lock()

1、NonfairSync.lock() 方法流程圖:

ReentrantLock是什么意思

2、lock方法詳解

在初始化 ReentrantLock 的時(shí)候,如果我們不傳參,使用默認(rèn)的構(gòu)造函數(shù),那么默認(rèn)使用非公平鎖,也就是 NonfairSync2) 當(dāng)我們調(diào)用  ReentrantLock 的 lock() 方法的時(shí)候,實(shí)際上是調(diào)用了 NonfairSync 的 lock() 方法,代碼如下:

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() {           //這個(gè)方法先用CAS操作,去嘗試搶占該鎖           // 快速嘗試將state從0設(shè)置成1,如果state=0代表當(dāng)前沒(méi)有任何一個(gè)線程獲得了鎖             if (compareAndSetState(0, 1))               //state設(shè)置成1代表獲得鎖成功               //如果成功,就把當(dāng)前線程設(shè)置在這個(gè)鎖上,表示搶占成功,在重入鎖的時(shí)候需要                 setExclusiveOwnerThread(Thread.currentThread());             else               //如果失敗,則調(diào)用 AbstractQueuedSynchronizer.acquire() 模板方法,等待搶占。                 acquire(1);         }          protected final boolean tryAcquire(int acquires) {             return nonfairTryAcquire(acquires);         }     }

調(diào)用 acquire(1) 實(shí)際上使用的是 AbstractQueuedSynchronizer 的acquire()  方法,它是一套鎖搶占的模板,acquire() 代碼比較簡(jiǎn)單:

public final void acquire(int arg) {       //先去嘗試獲取鎖,如果沒(méi)有獲取成功,就在CLH隊(duì)列中增加一個(gè)當(dāng)前線程的節(jié)點(diǎn),表示等待搶占。       //然后進(jìn)入CLH隊(duì)列的搶占模式,進(jìn)入的時(shí)候也會(huì)去執(zhí)行一次獲取鎖的操作,如果還是獲取不到,       //就調(diào)用LockSupport.park() 將當(dāng)前線程掛起。那么當(dāng)前線程什么時(shí)候會(huì)被喚醒呢?當(dāng)       //持有鎖的那個(gè)線程調(diào)用 unlock() 的時(shí)候,會(huì)將CLH隊(duì)列的頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)上的線程       //喚醒,調(diào)用的是 LockSupport.unpark() 方法。         if (!tryAcquire(arg) &&             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))             selfInterrupt();     }

acquire() 會(huì)先調(diào)用 tryAcquire() 這個(gè)鉤子方法去嘗試獲取鎖,這個(gè)方法就是在 NonfairSync.tryAcquire()下的  nonfairTryAcquire(),源碼如下:

//一個(gè)嘗試插隊(duì)的過(guò)程   final boolean nonfairTryAcquire(int acquires) {             final Thread current = Thread.currentThread();             //獲取state值             int c = getState();             //比較鎖的狀態(tài)是否為 0,如果是0,當(dāng)前沒(méi)有任何一個(gè)線程獲取鎖             if (c == 0) {               //則嘗試去原子搶占這個(gè)鎖(設(shè)置狀態(tài)為1,然后把當(dāng)前線程設(shè)置成獨(dú)占線程)                 if (compareAndSetState(0, acquires)) {                   // 設(shè)置成功標(biāo)識(shí)獨(dú)占鎖                     setExclusiveOwnerThread(current);                     return true;                 }             }             //如果當(dāng)前鎖的狀態(tài)不是0 state!=0,就去比較當(dāng)前線程和占用鎖的線程是不是一個(gè)線程             else if (current == getExclusiveOwnerThread()) {               //如果是,增加狀態(tài)變量的值,從這里看出可重入鎖之所以可重入,就是同一個(gè)線程可以反復(fù)使用它占用的鎖                 int nextc = c + acquires;                 //重入次數(shù)太多,大過(guò)Integer.MAX                 if (nextc < 0) // overflow                     throw new Error("Maximum lock count exceeded");                 setState(nextc);                 return true;             }             //如果以上兩種情況都不通過(guò),則返回失敗false             return false;         }

tryAcquire() 一旦返回 false,就會(huì)則進(jìn)入 acquireQueued()  流程,也就是基于CLH隊(duì)列的搶占模式,在CLH鎖隊(duì)列尾部增加一個(gè)等待節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)保存了當(dāng)前線程,通過(guò)調(diào)用 addWaiter()  實(shí)現(xiàn),這里需要考慮初始化的情況,在第一個(gè)等待節(jié)點(diǎn)進(jìn)入的時(shí)候,需要初始化一個(gè)頭節(jié)點(diǎn)然后把當(dāng)前節(jié)點(diǎn)加入到尾部,后續(xù)則直接在尾部加入節(jié)點(diǎn)。

代碼如下:

//AbstractQueuedSynchronizer.addWaiter()   private Node addWaiter(Node mode) {       // 初始化一個(gè)節(jié)點(diǎn),用于保存當(dāng)前線程         Node node = new Node(Thread.currentThread(), mode);         // 當(dāng)CLH隊(duì)列不為空的視乎,直接在隊(duì)列尾部插入一個(gè)節(jié)點(diǎn)         Node pred = tail;         if (pred != null) {             node.prev = pred;             //如果pred還是尾部(即沒(méi)有被其他線程更新),則將尾部更新為node節(jié)點(diǎn)(即當(dāng)前線程快速設(shè)置成了隊(duì)尾)             if (compareAndSetTail(pred, node)) {                 pred.next = node;                 return node;             }         }         // 當(dāng)CLH隊(duì)列為空的時(shí)候,調(diào)用enq方法初始化隊(duì)列         enq(node);         return node;     }              private Node enq(final Node node) {         //在一個(gè)循環(huán)里不停的嘗試將node節(jié)點(diǎn)插入到隊(duì)尾里         for (;;) {             Node t = tail;             if (t == null) { // 初始化節(jié)點(diǎn),頭尾都指向一個(gè)空節(jié)點(diǎn)                 if (compareAndSetHead(new Node()))                     tail = head;             } else {                 node.prev = t;                 if (compareAndSetTail(t, node)) {                     t.next = node;                     return t;                 }             }         }     }

將節(jié)點(diǎn)增加到CLH隊(duì)列后,進(jìn)入 acquireQueued() 方法

final boolean acquireQueued(final Node node, int arg) {         boolean failed = true;         try {             boolean interrupted = false;             //在一個(gè)循環(huán)里不斷等待前驅(qū)節(jié)點(diǎn)執(zhí)行完畢             for (;;) {                 final Node p = node.predecessor();                 if (p == head && tryAcquire(arg)) {// 通過(guò)tryAcquire獲得鎖,如果獲取到鎖,說(shuō)明頭節(jié)點(diǎn)已經(jīng)釋放了鎖                     setHead(node);//將當(dāng)前節(jié)點(diǎn)設(shè)置成頭節(jié)點(diǎn)                     p.next = null; // help GC//將上一個(gè)節(jié)點(diǎn)的next變量被設(shè)置為null,在下次GC的時(shí)候會(huì)清理掉                     failed = false;//將failed標(biāo)記設(shè)置成false                     return interrupted;                 }                 //中斷                 if (shouldParkAfterFailedAcquire(p, node) && // 是否需要阻塞                     parkAndCheckInterrupt())// 阻塞,返回線程是否被中斷                     interrupted = true;             }         } finally {             if (failed)                 cancelAcquire(node);         }     }

如果嘗試獲取鎖失敗,就會(huì)進(jìn)入 shouldParkAfterFailedAcquire() 方法,會(huì)判斷當(dāng)前線程是否阻塞

/**   * 確保當(dāng)前結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn)的狀態(tài)為SIGNAL   * SIGNAL意味著線程釋放鎖后會(huì)喚醒后面阻塞的線程   * 只有確保能夠被喚醒,當(dāng)前線程才能放心的阻塞。   */     private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {         int ws = pred.waitStatus;         if (ws == Node.SIGNAL)            //如果前驅(qū)節(jié)點(diǎn)狀態(tài)為SIGNAL            //表明當(dāng)前線程需要阻塞,因?yàn)榍爸霉?jié)點(diǎn)承諾執(zhí)行完之后會(huì)通知喚醒當(dāng)前節(jié)點(diǎn)             return true;         if (ws > 0) {//ws > 0 代表前驅(qū)節(jié)點(diǎn)取消了                         do {                 node.prev = pred = pred.prev;//不斷的把前驅(qū)取消了的節(jié)點(diǎn)移除隊(duì)列             } while (pred.waitStatus > 0);             pred.next = node;         } else {           //初始化狀態(tài),將前驅(qū)節(jié)點(diǎn)的狀態(tài)設(shè)置成SIGNAL             compareAndSetWaitStatus(pred, ws, Node.SIGNAL);         }         return false;     }

當(dāng)進(jìn)入阻塞階段,會(huì)進(jìn)入parkAndCheckInterrupt() 方法,則會(huì)調(diào)用 LockSupport.park(this)  將當(dāng)前線程掛起。代碼如下:

// 從方法名可以看出這個(gè)方法做了兩件事 private final boolean parkAndCheckInterrupt() {     LockSupport.park(this);//掛起當(dāng)前的線程     // 如果當(dāng)前線程已經(jīng)被中斷了,返回true,否則返回false     // 有可能在掛起階段被中斷了     return Thread.interrupted(); }

4.2 非公平鎖 NonfairSync.unlock()

2.1 unlock()方法的示意圖

ReentrantLock是什么意思

2.1 unlock()方法詳解1) 調(diào)用 unlock() 方法,其實(shí)是直接調(diào)用  AbstractQueuedSynchronizer.release() 操作。

2) 進(jìn)入 release() 方法,內(nèi)部先嘗試 tryRelease()  操作,主要是去除鎖的獨(dú)占線程,然后將狀態(tài)減一,這里減一主要是考慮到可重入鎖可能自身會(huì)多次占用鎖,只有當(dāng)狀態(tài)變成0,才表示完全釋放了鎖。

3) 如果 tryRelease 成功,則將CHL隊(duì)列的頭節(jié)點(diǎn)的狀態(tài)設(shè)置為0,然后喚醒下一個(gè)非取消的節(jié)點(diǎn)線程。

4) 一旦下一個(gè)節(jié)點(diǎn)的線程被喚醒,被喚醒的線程就會(huì)進(jìn)入 acquireQueued() 代碼流程中,去獲取鎖。

代碼如下:

public void unlock() {         sync.release(1); }   public final boolean release(int arg) {     //嘗試在當(dāng)前鎖的鎖定計(jì)數(shù)(state)值上減1,         if (tryRelease(arg)) {             Node h = head;             if (h != null && h.waitStatus != 0)//waitStatus!=0表明或者處于CANCEL狀態(tài),或者是SIGNAL表示下一個(gè)線程在等待其喚醒。也就是說(shuō)waitStatus不為零表示它的后繼在等待喚醒。                 unparkSuccessor(h);                //成功返回true             return true;         }         //否則返回false         return false; }  private void unparkSuccessor(Node node) {         int ws = node.waitStatus;          //如果waitStatus < 0 則將當(dāng)前節(jié)點(diǎn)清零         if (ws < 0)             compareAndSetWaitStatus(node, ws, 0);     //若后續(xù)節(jié)點(diǎn)為空或已被cancel,則從尾部開(kāi)始找到隊(duì)列中第一個(gè)waitStatus<=0,即未被cancel的節(jié)點(diǎn)         Node s = node.next;         if (s == null || s.waitStatus > 0) {             s = null;             for (Node t = tail; t != null && t != node; t = t.prev)                 if (t.waitStatus <= 0)                     s = t;         }         if (s != null)             LockSupport.unpark(s.thread);     }

當(dāng)然在 release() 方法中不僅僅只是將 state - 1 這么簡(jiǎn)單,-1 之后還需要進(jìn)行一番處理,如果 -1 之后的 新state = 0  ,則表示當(dāng)前鎖已經(jīng)被線程釋放了,同時(shí)會(huì)喚醒線程等待隊(duì)列中的下一個(gè)線程。

protected final boolean tryRelease(int releases) {      int c = getState() - releases;     //判斷是否為當(dāng)前線程在調(diào)用,不是拋出IllegalMonitorStateException異常     if (Thread.currentThread() != getExclusiveOwnerThread())                 throw new IllegalMonitorStateException();     boolean free = false;    //c == 0,釋放該鎖,同時(shí)將當(dāng)前所持有線程設(shè)置為null     if (c == 0) {           free = true;           setExclusiveOwnerThread(null);     }     //設(shè)置state     setState(c);     return free;  }  private void unparkSuccessor(Node node) {         int ws = node.waitStatus;         if (ws < 0)             compareAndSetWaitStatus(node, ws, 0);         Node s = node.next;         if (s == null || s.waitStatus > 0) {             s = null;             // 從后往前找到離head最近,而且waitStatus <= 0 的節(jié)點(diǎn)             // 其實(shí)在ReentrantLock中,waitStatus應(yīng)該只能為0和-1,需要喚醒的都是-1(Node.SIGNAL)             for (Node t = tail; t != null && t != node; t = t.prev)                 if (t.waitStatus <= 0)                     s = t;         }         if (s != null)              LockSupport.unpark(s.thread);// 喚醒掛起線程 }

重點(diǎn):unlock最好放在finally中,因?yàn)槿绻麤](méi)有使用finally來(lái)釋放Lock,那么相當(dāng)于啟動(dòng)了一個(gè)定時(shí)炸彈,如果發(fā)生錯(cuò)誤,我們很難追蹤到最初發(fā)生錯(cuò)誤的位置,因?yàn)闆](méi)有記錄應(yīng)該釋放鎖的位置和時(shí)間,這也就是  ReentrantLock 不能完全替代 synchronized 的原因,因?yàn)楫?dāng)程序執(zhí)行控制離開(kāi)被保護(hù)的代碼塊時(shí),不會(huì)自動(dòng)清除鎖。

4.3 公平鎖 FairSync

FairSync相對(duì)來(lái)說(shuō)就簡(jiǎn)單很多,只有重寫的兩個(gè)方法跟NonfairSync不同

final void lock() {     acquire(1); }  protected final boolean tryAcquire(int acquires) {     final Thread current = Thread.currentThread();     int c = getState();     if (c == 0) {         if (!hasQueuedPredecessors() &&// 沒(méi)有前驅(qū)節(jié)點(diǎn)了             compareAndSetState(0, acquires)) {// 而且沒(méi)有鎖             setExclusiveOwnerThread(current);             return true;         }     }     else if (current == getExclusiveOwnerThread()) {         int nextc = c + acquires;         if (nextc < 0)             throw new Error("Maximum lock count exceeded");         setState(nextc);         return true;     }     return false; }

五、公平鎖和非公平鎖的區(qū)別

  • 鎖的公平性是相對(duì)于獲取鎖的順序而言的。

  • 如果是一個(gè)公平鎖,那么鎖的獲取順序就應(yīng)該符合請(qǐng)求的絕對(duì)時(shí)間順序,也就是FIFO,線程獲取鎖的順序和調(diào)用lock的順序一樣,能夠保證老的線程排隊(duì)使用鎖,新線程仍然排隊(duì)使用鎖。

  • 非公平鎖只要CAS設(shè)置同步狀態(tài)成功,則表示當(dāng)前線程獲取了鎖,線程獲取鎖的順序和調(diào)用lock的順序無(wú)關(guān),全憑運(yùn)氣,也就是老的線程排隊(duì)使用鎖,但是無(wú)法保證新線程搶占已經(jīng)在排隊(duì)的線程的鎖。

  • ReentrantLock默認(rèn)使用非公平鎖是基于性能考慮,公平鎖為了保證線程規(guī)規(guī)矩矩地排隊(duì),需要增加阻塞和喚醒的時(shí)間開(kāi)銷。如果直接插隊(duì)獲取非公平鎖,跳過(guò)了對(duì)隊(duì)列的處理,速度會(huì)更快。

六、ReenTrantLock(可重入鎖)  和 synchronized的區(qū)別

6.1 可重入性

ReenTrantLock(可重入鎖) 的字面意思就是再進(jìn)入的鎖,對(duì)于 synchronized  關(guān)鍵字所使用的鎖也是可重入的,兩者關(guān)于這個(gè)的區(qū)別不大。兩者都是同一個(gè)線程沒(méi)進(jìn)入一次,鎖的計(jì)數(shù)器都自增1,所以要等到鎖的計(jì)數(shù)器下降為0時(shí)才能釋放鎖。

6.2  鎖的實(shí)現(xiàn)

Synchronized 是依賴于JVM實(shí)現(xiàn)的,而 ReenTrantLock  是JDK實(shí)現(xiàn)的,有什么區(qū)別,說(shuō)白了就類似于操作系統(tǒng)來(lái)控制實(shí)現(xiàn)和用戶自己敲代碼實(shí)現(xiàn)的區(qū)別。前者的實(shí)現(xiàn)是比較難見(jiàn)到的,后者有直接的源碼可供閱讀。

6.3  性能的區(qū)別

在Synchronized優(yōu)化以前,synchronized的性能是比ReenTrantLock差很多的,但是自從Synchronized引入了偏向鎖,輕量級(jí)鎖(自旋鎖)后,兩者的性能就差不多了,在兩種方法都可用的情況下,官方甚至建議使用synchronized,其實(shí)synchronized的優(yōu)化我感覺(jué)就借鑒了ReenTrantLock中的CAS技術(shù)。都是試圖在用戶態(tài)就把加鎖問(wèn)題解決,避免進(jìn)入內(nèi)核態(tài)的線程阻塞。

6.4  功能區(qū)別

便利性:很明顯Synchronized的使用比較方便簡(jiǎn)潔,并且由編譯器去保證鎖的加鎖和釋放,而ReenTrantLock需要手工聲明來(lái)加鎖和釋放鎖,為了避免忘記手工釋放鎖造成死鎖,所以最好在finally中聲明釋放鎖。

鎖的細(xì)粒度和靈活度:很明顯 ReenTrantLock 優(yōu)于 Synchronized ,但是 ReenTrantLock 沒(méi)有辦法完全取代  Synchronized

ReenTrantLock獨(dú)有的能力

1) ReenTrantLock 可以指定是公平鎖還是非公平鎖。而 synchronized  只能是非公平鎖。所謂的公平鎖就是先等待的線程先獲得鎖。

2) ReenTrantLock 提供了一個(gè) Condition(條件)類,用來(lái)實(shí)現(xiàn)分組喚醒需要喚醒的線程們,而不是像synchronized  要么隨機(jī)喚醒一個(gè)線程要么喚醒全部線程。

3) ReenTrantLock 提供了一種能夠中斷等待鎖的線程的機(jī)制,通過(guò) lock.lockInterruptibly() 來(lái)實(shí)現(xiàn)這個(gè)機(jī)制。

七、總結(jié)

ReentrantLock 是java中非常重要的一個(gè)并發(fā)工具,相比于java原生的 synchronized 有著更好的性能,學(xué)習(xí)  ReentrantLock ,我們主要需要了解它,公平鎖 和 非公平鎖  的實(shí)現(xiàn),以及重入鎖的獲取與釋放的流程,還有最重要的就是要了解AQS(AbstractQueuedSynchronizer),這是實(shí)現(xiàn)重入鎖的基礎(chǔ),ReentrantLock  是一個(gè)比較輕量級(jí)的鎖,而且使用面向?qū)ο蟮乃枷肴?shí)現(xiàn)了鎖的功能,比原來(lái)的synchronized 關(guān)鍵字更加好理解。

“ReentrantLock是什么意思”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向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