您好,登錄后才能下訂單哦!
本篇內(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í)功能。
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實(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)成功釋放。
使用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ú)法釋放。
在簡(jiǎn)介中我們知道 ReentrantLock繼承自 Lock接口, Lock提供了一些獲取鎖和釋放鎖的方法,以及條件判斷的獲取的方法,通過(guò)實(shí)現(xiàn)它來(lái)進(jìn)行鎖的控制,因?yàn)樗秋@示鎖,所以需要顯示指定起始位置和終止位置,下面就來(lái)介紹一下 Lock接口的方法介紹:
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() 方法:
1、NonfairSync.lock() 方法流程圖:
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(); }
2.1 unlock()方法的示意圖
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)清除鎖。
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; }
鎖的公平性是相對(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(可重入鎖) 的字面意思就是再進(jìn)入的鎖,對(duì)于 synchronized 關(guān)鍵字所使用的鎖也是可重入的,兩者關(guān)于這個(gè)的區(qū)別不大。兩者都是同一個(gè)線程沒(méi)進(jìn)入一次,鎖的計(jì)數(shù)器都自增1,所以要等到鎖的計(jì)數(shù)器下降為0時(shí)才能釋放鎖。
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)到的,后者有直接的源碼可供閱讀。
在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)的線程阻塞。
便利性:很明顯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ī)制。
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í)用文章!
免責(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)容。