ReentrantLock源碼詳解--公平鎖、非公平鎖
問(wèn)題
(1)重入鎖是什么?
(2)ReentrantLock如何實(shí)現(xiàn)重入鎖?
(3)ReentrantLock為什么默認(rèn)是非公平模式?
(4)ReentrantLock除了可重入還有哪些特性?
簡(jiǎn)介
Reentrant = Re + entrant,Re是重復(fù)、又、再的意思,entrant是enter的名詞或者形容詞形式,翻譯為進(jìn)入者或者可進(jìn)入的,所以Reentrant翻譯為可重復(fù)進(jìn)入的、可再次進(jìn)入的,因此ReentrantLock翻譯為重入鎖或者再入鎖。
重入鎖,是指一個(gè)線(xiàn)程獲取鎖之后再?lài)L試獲取鎖時(shí)會(huì)自動(dòng)獲取鎖。
在Java中,除了ReentrantLock以外,synchronized也是重入鎖。
那么,ReentrantLock的可重入性是怎么實(shí)現(xiàn)的呢?
繼承體系
ReentrantLock實(shí)現(xiàn)了Lock接口,Lock接口里面定義了java中鎖應(yīng)該實(shí)現(xiàn)的幾個(gè)方法:
// 獲取鎖 void lock(); // 獲取鎖(可中斷) void lockInterruptibly() throws InterruptedException; // 嘗試獲取鎖,如果沒(méi)獲取到鎖,就返回false boolean tryLock(); // 嘗試獲取鎖,如果沒(méi)獲取到鎖,就等待一段時(shí)間,這段時(shí)間內(nèi)還沒(méi)獲取到鎖就返回false boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 釋放鎖 void unlock(); // 條件鎖 Condition newCondition();
Lock接口中主要定義了 獲取鎖、嘗試獲取鎖、釋放鎖、條件鎖等幾個(gè)方法。
源碼分析
主要內(nèi)部類(lèi)
ReentrantLock中主要定義了三個(gè)內(nèi)部類(lèi):Sync、NonfairSync、FairSync。
abstract static class Sync extends AbstractQueuedSynchronizer {} static final class NonfairSync extends Sync {} static final class FairSync extends Sync {}
(1)抽象類(lèi)Sync實(shí)現(xiàn)了AQS的部分方法;
(2)NonfairSync實(shí)現(xiàn)了Sync,主要用于非公平鎖的獲取;
(3)FairSync實(shí)現(xiàn)了Sync,主要用于公平鎖的獲取。
在這里我們先不急著看每個(gè)類(lèi)具體的代碼,等下面學(xué)習(xí)具體的功能點(diǎn)的時(shí)候再把所有方法串起來(lái)。
主要屬性
private final Sync sync;
主要屬性就一個(gè)sync,它在構(gòu)造方法中初始化,決定使用公平鎖還是非公平鎖的方式獲取鎖。
主要構(gòu)造方法
// 默認(rèn)構(gòu)造方法 public ReentrantLock() { sync = new NonfairSync(); } // 自己可選擇使用公平鎖還是非公平鎖 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
(1)默認(rèn)構(gòu)造方法使用的是非公平鎖;
(2)第二個(gè)構(gòu)造方法可以自己決定使用公平鎖還是非公平鎖;
上面我們分析了ReentrantLock的主要結(jié)構(gòu),下面我們跟著幾個(gè)主要方法來(lái)看源碼。
lock()方法
彤哥貼心地在每個(gè)方法的注釋都加上方法的來(lái)源。
1.公平鎖
這里我們假設(shè)ReentrantLock的實(shí)例是通過(guò)以下方式獲得的:
ReentrantLock reentrantLock = new ReentrantLock(true);
下面的是加鎖的主要邏輯:
// ReentrantLock.lock() public void lock() { // 調(diào)用的sync屬性的lock()方法 // 這里的sync是公平鎖,所以是FairSync的實(shí)例 sync.lock(); } // ReentrantLock.FairSync.lock() final void lock() { // 調(diào)用AQS的acquire()方法獲取鎖 // 注意,這里傳的值為1 acquire(1); } // AbstractQueuedSynchronizer.acquire() public final void acquire(int arg) { // 嘗試獲取鎖 // 如果失敗了,就排隊(duì) if (!tryAcquire(arg) && // 注意addWaiter()這里傳入的節(jié)點(diǎn)模式為獨(dú)占模式 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } // ReentrantLock.FairSync.tryAcquire() protected final boolean tryAcquire(int acquires) { // 當(dāng)前線(xiàn)程 final Thread current = Thread.currentThread(); // 查看當(dāng)前狀態(tài)變量的值 int c = getState(); // 如果狀態(tài)變量的值為0,說(shuō)明暫時(shí)還沒(méi)有人占有鎖 if (c == 0) { // 如果沒(méi)有其它線(xiàn)程在排隊(duì),那么當(dāng)前線(xiàn)程嘗試更新state的值為1 // 如果成功了,則說(shuō)明當(dāng)前線(xiàn)程獲取了鎖 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { // 當(dāng)前線(xiàn)程獲取了鎖,把自己設(shè)置到exclusiveOwnerThread變量中 // exclusiveOwnerThread是AQS的父類(lèi)AbstractOwnableSynchronizer中提供的變量 setExclusiveOwnerThread(current); // 返回true說(shuō)明成功獲取了鎖 return true; } } // 如果當(dāng)前線(xiàn)程本身就占有著鎖,現(xiàn)在又嘗試獲取鎖 // 那么,直接讓它獲取鎖并返回true else if (current == getExclusiveOwnerThread()) { // 狀態(tài)變量state的值加1 int nextc = c + acquires; // 如果溢出了,則報(bào)錯(cuò) if (nextc < 0) throw new Error("Maximum lock count exceeded"); // 設(shè)置到state中 // 這里不需要CAS更新state // 因?yàn)楫?dāng)前線(xiàn)程占有著鎖,其它線(xiàn)程只會(huì)CAS把state從0更新成1,是不會(huì)成功的 // 所以不存在競(jìng)爭(zhēng),自然不需要使用CAS來(lái)更新 setState(nextc); // 當(dāng)線(xiàn)程獲取鎖成功 return true; } // 當(dāng)前線(xiàn)程嘗試獲取鎖失敗 return false; } // AbstractQueuedSynchronizer.addWaiter() // 調(diào)用這個(gè)方法,說(shuō)明上面嘗試獲取鎖失敗了 private Node addWaiter(Node mode) { // 新建一個(gè)節(jié)點(diǎn) Node node = new Node(Thread.currentThread(), mode); // 這里先嘗試把新節(jié)點(diǎn)加到尾節(jié)點(diǎn)后面 // 如果成功了就返回新節(jié)點(diǎn) // 如果沒(méi)成功再調(diào)用enq()方法不斷嘗試 Node pred = tail; // 如果尾節(jié)點(diǎn)不為空 if (pred != null) { // 設(shè)置新節(jié)點(diǎn)的前置節(jié)點(diǎn)為現(xiàn)在的尾節(jié)點(diǎn) node.prev = pred; // CAS更新尾節(jié)點(diǎn)為新節(jié)點(diǎn) if (compareAndSetTail(pred, node)) { // 如果成功了,把舊尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)指向新節(jié)點(diǎn) pred.next = node; // 并返回新節(jié)點(diǎn) return node; } } // 如果上面嘗試入隊(duì)新節(jié)點(diǎn)沒(méi)成功,調(diào)用enq()處理 enq(node); return node; } // AbstractQueuedSynchronizer.enq() private Node enq(final Node node) { // 自旋,不斷嘗試 for (;;) { Node t = tail; // 如果尾節(jié)點(diǎn)為空,說(shuō)明還未初始化 if (t == null) { // Must initialize // 初始化頭節(jié)點(diǎn)和尾節(jié)點(diǎn) if (compareAndSetHead(new Node())) tail = head; } else { // 如果尾節(jié)點(diǎn)不為空 // 設(shè)置新節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)為現(xiàn)在的尾節(jié)點(diǎn) node.prev = t; // CAS更新尾節(jié)點(diǎn)為新節(jié)點(diǎn) if (compareAndSetTail(t, node)) { // 成功了,則設(shè)置舊尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)為新節(jié)點(diǎn) t.next = node; // 并返回舊尾節(jié)點(diǎn) return t; } } } } // AbstractQueuedSynchronizer.acquireQueued() // 調(diào)用上面的addWaiter()方法使得新節(jié)點(diǎn)已經(jīng)成功入隊(duì)了 // 這個(gè)方法是嘗試讓當(dāng)前節(jié)點(diǎn)來(lái)獲取鎖的 final boolean acquireQueued(final Node node, int arg) { // 失敗標(biāo)記 boolean failed = true; try { // 中斷標(biāo)記 boolean interrupted = false; // 自旋 for (;;) { // 當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn) final Node p = node.predecessor(); // 如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)為head節(jié)點(diǎn),則說(shuō)明輪到自己獲取鎖了 // 調(diào)用ReentrantLock.FairSync.tryAcquire()方法再次嘗試獲取鎖 if (p == head && tryAcquire(arg)) { // 嘗試獲取鎖成功 // 這里同時(shí)只會(huì)有一個(gè)線(xiàn)程在執(zhí)行,所以不需要用CAS更新 // 把當(dāng)前節(jié)點(diǎn)設(shè)置為新的頭節(jié)點(diǎn) setHead(node); // 并把上一個(gè)節(jié)點(diǎn)從鏈表中刪除 p.next = null; // help GC // 未失敗 failed = false; return interrupted; } // 是否需要阻塞 if (shouldParkAfterFailedAcquire(p, node) && // 真正阻塞的方法 parkAndCheckInterrupt()) // 如果中斷了 interrupted = true; } } finally { // 如果失敗了 if (failed) // 取消獲取鎖 cancelAcquire(node); } } // AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire() // 這個(gè)方法是在上面的for()循環(huán)里面調(diào)用的 // 第一次調(diào)用會(huì)把前一個(gè)節(jié)點(diǎn)的等待狀態(tài)設(shè)置為SIGNAL,并返回false // 第二次調(diào)用才會(huì)返回true private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { // 上一個(gè)節(jié)點(diǎn)的等待狀態(tài) // 注意Node的waitStatus字段我們?cè)谏厦鎰?chuàng)建Node的時(shí)候并沒(méi)有指定 // 也就是說(shuō)使用的是默認(rèn)值0 // 這里把各種等待狀態(tài)再貼出來(lái) //static final int CANCELLED = 1; //static final int SIGNAL = -1; //static final int CONDITION = -2; //static final int PROPAGATE = -3; int ws = pred.waitStatus; // 如果等待狀態(tài)為SIGNAL(等待喚醒),直接返回true if (ws == Node.SIGNAL) return true; // 如果前一個(gè)節(jié)點(diǎn)的狀態(tài)大于0,也就是已取消狀態(tài) if (ws > 0) { // 把前面所有取消狀態(tài)的節(jié)點(diǎn)都從鏈表中刪除 do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { // 如果前一個(gè)節(jié)點(diǎn)的狀態(tài)小于等于0,則把其狀態(tài)設(shè)置為等待喚醒 // 這里可以簡(jiǎn)單地理解為把初始狀態(tài)0設(shè)置為SIGNAL // CONDITION是條件鎖的時(shí)候使用的 // PROPAGATE是共享鎖使用的 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } // AbstractQueuedSynchronizer.parkAndCheckInterrupt() private final boolean parkAndCheckInterrupt() { // 阻塞當(dāng)前線(xiàn)程 // 底層調(diào)用的是Unsafe的park()方法 LockSupport.park(this); // 返回是否已中斷 return Thread.interrupted(); }
下面我們看一下主要方法的調(diào)用關(guān)系,可以跟著我的 → 層級(jí)在腦海中大概過(guò)一遍每個(gè)方法的主要代碼:
ReentrantLock#lock() ->ReentrantLock.FairSync#lock() // 公平模式獲取鎖 ->AbstractQueuedSynchronizer#acquire() // AQS的獲取鎖方法 ->ReentrantLock.FairSync#tryAcquire() // 嘗試獲取鎖 ->AbstractQueuedSynchronizer#addWaiter() // 添加到隊(duì)列 ->AbstractQueuedSynchronizer#enq() // 入隊(duì) ->AbstractQueuedSynchronizer#acquireQueued() // 里面有個(gè)for()循環(huán),喚醒后再次嘗試獲取鎖 ->AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire() // 檢查是否要阻塞 ->AbstractQueuedSynchronizer#parkAndCheckInterrupt() // 真正阻塞的地方
獲取鎖的主要過(guò)程大致如下:
(1)嘗試獲取鎖,如果獲取到了就直接返回了;
(2)嘗試獲取鎖失敗,再調(diào)用addWaiter()構(gòu)建新節(jié)點(diǎn)并把新節(jié)點(diǎn)入隊(duì);
(3)然后調(diào)用acquireQueued()再次嘗試獲取鎖,如果成功了,直接返回;
(4)如果再次失敗,再調(diào)用shouldParkAfterFailedAcquire()將節(jié)點(diǎn)的等待狀態(tài)置為等待喚醒(SIGNAL);
(5)調(diào)用parkAndCheckInterrupt()阻塞當(dāng)前線(xiàn)程;
(6)如果被喚醒了,會(huì)繼續(xù)在acquireQueued()的for()循環(huán)再次嘗試獲取鎖,如果成功了就返回;
(7)如果不成功,再次阻塞,重復(fù)(3)(4)(5)直到成功獲取到鎖。
以上就是整個(gè)公平鎖獲取鎖的過(guò)程,下面我們看看非公平鎖是怎么獲取鎖的。
2.非公平鎖
// ReentrantLock.lock() public void lock() { sync.lock(); } // ReentrantLock.NonfairSync.lock() // 這個(gè)方法在公平鎖模式下是直接調(diào)用的acquire(1); final void lock() { // 直接嘗試CAS更新?tīng)顟B(tài)變量 if (compareAndSetState(0, 1)) // 如果更新成功,說(shuō)明獲取到鎖,把當(dāng)前線(xiàn)程設(shè)為獨(dú)占線(xiàn)程 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } // ReentrantLock.NonfairSync.tryAcquire() protected final boolean tryAcquire(int acquires) { // 調(diào)用父類(lèi)的方法 return nonfairTryAcquire(acquires); } // ReentrantLock.Sync.nonfairTryAcquire() final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 如果狀態(tài)變量的值為0,再次嘗試CAS更新?tīng)顟B(tài)變量的值 // 相對(duì)于公平鎖模式少了!hasQueuedPredecessors()條件 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
相對(duì)于公平鎖,非公平鎖加鎖的過(guò)程主要有兩點(diǎn)不同:
(1)一開(kāi)始就嘗試CAS更新?tīng)顟B(tài)變量state的值,如果成功了就獲取到鎖了;
(2)在tryAcquire()的時(shí)候沒(méi)有檢查是否前面有排隊(duì)的線(xiàn)程,直接上去獲取鎖才不管別人有沒(méi)有排隊(duì)呢;
總的來(lái)說(shuō),相對(duì)于公平鎖,非公平鎖在一開(kāi)始就多了兩次直接嘗試獲取鎖的過(guò)程。
lockInterruptibly()方法
支持線(xiàn)程中斷,它與lock()方法的主要區(qū)別在于lockInterruptibly()獲取鎖的時(shí)候如果線(xiàn)程中斷了,會(huì)拋出一個(gè)異常,而lock()不會(huì)管線(xiàn)程是否中斷都會(huì)一直嘗試獲取鎖,獲取鎖之后把自己標(biāo)記為已中斷,繼續(xù)執(zhí)行自己的邏輯,后面也會(huì)正常釋放鎖。
題外話(huà):
線(xiàn)程中斷,只是在線(xiàn)程上打一個(gè)中斷標(biāo)志,并不會(huì)對(duì)運(yùn)行中的線(xiàn)程有什么影響,具體需要根據(jù)這個(gè)中斷標(biāo)志干些什么,用戶(hù)自己去決定。
比如,如果用戶(hù)在調(diào)用lock()獲取鎖后,發(fā)現(xiàn)線(xiàn)程中斷了,就直接返回了,而導(dǎo)致沒(méi)有釋放鎖,這也是允許的,但是會(huì)導(dǎo)致這個(gè)鎖一直得不到釋放,就出現(xiàn)了死鎖。
lock.lock(); if (Thread.currentThread().interrupted()) { return ; } lock.unlock();
當(dāng)然,這里只是舉個(gè)例子,實(shí)際使用肯定是要把lock.lock()后面的代碼都放在try...finally...里面的以保證鎖始終會(huì)釋放,這里主要是為了說(shuō)明線(xiàn)程中斷只是一個(gè)標(biāo)志,至于要做什么完全由用戶(hù)自己決定。
tryLock()方法
嘗試獲取一次鎖,成功了就返回true,沒(méi)成功就返回false,不會(huì)繼續(xù)嘗試。
// ReentrantLock.tryLock() public boolean tryLock() { // 直接調(diào)用Sync的nonfairTryAcquire()方法 return sync.nonfairTryAcquire(1); } // ReentrantLock.Sync.nonfairTryAcquire() final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
tryLock()方法比較簡(jiǎn)單,直接以非公平的模式去嘗試獲取一次鎖,獲取到了或者鎖本來(lái)就是當(dāng)前線(xiàn)程占有著就返回true,否則返回false。
tryLock(long time, TimeUnit unit)方法
嘗試獲取鎖,并等待一段時(shí)間,如果在這段時(shí)間內(nèi)都沒(méi)有獲取到鎖,就返回false。
// ReentrantLock.tryLock() public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { // 調(diào)用AQS中的方法 return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } // AbstractQueuedSynchronizer.tryAcquireNanos() public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { // 如果線(xiàn)程中斷了,拋出異常 if (Thread.interrupted()) throw new InterruptedException(); // 先嘗試獲取一次鎖 return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout); } // AbstractQueuedSynchronizer.doAcquireNanos() private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { // 如果時(shí)間已經(jīng)到期了,直接返回false if (nanosTimeout <= 0L) return false; // 到期時(shí)間 final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return true; } nanosTimeout = deadline - System.nanoTime(); // 如果到期了,就直接返回false if (nanosTimeout <= 0L) return false; // spinForTimeoutThreshold = 1000L; // 只有到期時(shí)間大于1000納秒,才阻塞 // 小于等于1000納秒,直接自旋解決就得了 if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) // 阻塞一段時(shí)間 LockSupport.parkNanos(this, nanosTimeout); if (Thread.interrupted()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
tryLock(long time, TimeUnit unit)方法在阻塞的時(shí)候加上阻塞時(shí)間,并且會(huì)隨時(shí)檢查是否到期,只要到期了沒(méi)獲取到鎖就返回false。
unlock()方法
釋放鎖。
// java.util.concurrent.locks.ReentrantLock.unlock() public void unlock() { sync.release(1); } // java.util.concurrent.locks.AbstractQueuedSynchronizer.release public final boolean release(int arg) { // 調(diào)用AQS實(shí)現(xiàn)類(lèi)的tryRelease()方法釋放鎖 if (tryRelease(arg)) { Node h = head; // 如果頭節(jié)點(diǎn)不為空,且等待狀態(tài)不是0,就喚醒下一個(gè)節(jié)點(diǎn) // 還記得waitStatus嗎? // 在每個(gè)節(jié)點(diǎn)阻塞之前會(huì)把其上一個(gè)節(jié)點(diǎn)的等待狀態(tài)設(shè)為SIGNAL(-1) // 所以,SIGNAL的準(zhǔn)確理解應(yīng)該是喚醒下一個(gè)等待的線(xiàn)程 if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } // java.util.concurrent.locks.ReentrantLock.Sync.tryRelease protected final boolean tryRelease(int releases) { int c = getState() - releases; // 如果當(dāng)前線(xiàn)程不是占有著鎖的線(xiàn)程,拋出異常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 如果狀態(tài)變量的值為0了,說(shuō)明完全釋放了鎖 // 這也就是為什么重入鎖調(diào)用了多少次lock()就要調(diào)用多少次unlock()的原因 // 如果不這樣做,會(huì)導(dǎo)致鎖不會(huì)完全釋放,別的線(xiàn)程永遠(yuǎn)無(wú)法獲取到鎖 if (c == 0) { free = true; // 清空占有線(xiàn)程 setExclusiveOwnerThread(null); } // 設(shè)置狀態(tài)變量的值 setState(c); return free; } private void unparkSuccessor(Node node) { // 注意,這里的node是頭節(jié)點(diǎn) // 如果頭節(jié)點(diǎn)的等待狀態(tài)小于0,就把它設(shè)置為0 int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) Node s = node.next; // 如果下一個(gè)節(jié)點(diǎn)為空,或者其等待狀態(tài)大于0(實(shí)際為已取消) if (s == null || s.waitStatus > 0) { s = null; // 從尾節(jié)點(diǎn)向前遍歷取到隊(duì)列最前面的那個(gè)狀態(tài)不是已取消狀態(tài)的節(jié)點(diǎn) for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } // 如果下一個(gè)節(jié)點(diǎn)不為空,則喚醒它 if (s != null) LockSupport.unpark(s.thread); }
釋放鎖的過(guò)程大致為:
(1)將state的值減1;
(2)如果state減到了0,說(shuō)明已經(jīng)完全釋放鎖了,喚醒下一個(gè)等待著的節(jié)點(diǎn);
彩蛋
為什么ReentrantLock默認(rèn)采用的是非公平模式?
答:因?yàn)榉枪侥J叫时容^高。
為什么非公平模式效率比較高?
答:因?yàn)榉枪侥J綍?huì)在一開(kāi)始就嘗試兩次獲取鎖,如果當(dāng)時(shí)正好state的值為0,它就會(huì)成功獲取到鎖,少了排隊(duì)導(dǎo)致的阻塞/喚醒過(guò)程,并且減少了線(xiàn)程頻繁的切換帶來(lái)的性能損耗。
非公平模式有什么弊端?
答:非公平模式有可能會(huì)導(dǎo)致一開(kāi)始排隊(duì)的線(xiàn)程一直獲取不到鎖,導(dǎo)致線(xiàn)程餓死。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java中float類(lèi)型的范圍及其與十六進(jìn)制的轉(zhuǎn)換例子
這篇文章主要介紹了Java中float類(lèi)型的范圍及其與十六進(jìn)制的轉(zhuǎn)換例子,是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-10-10Java實(shí)現(xiàn)快速排序和堆排序的示例代碼
這篇文章主要為大家詳細(xì)介紹了快速排序和堆排序的多種語(yǔ)言的實(shí)現(xiàn)(JavaScript、Python、Go語(yǔ)言、Java、C++),感興趣的小伙伴可以了解一下2022-12-12詳解Java如何實(shí)現(xiàn)一個(gè)優(yōu)秀的散列表
這篇文章主要通過(guò)簡(jiǎn)單的示例為大家詳細(xì)介紹了在Java中如何實(shí)現(xiàn)一個(gè)優(yōu)秀的散列表,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以了解一下2023-07-07Java中用內(nèi)存映射處理大文件的實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇Java中用內(nèi)存映射處理大文件的實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06Java基于高精度整型實(shí)現(xiàn)fibonacci數(shù)列的方法
這篇文章主要介紹了Java基于高精度整型實(shí)現(xiàn)fibonacci數(shù)列的方法,是比較典型的算法,需要的朋友可以參考下2014-09-09SpringBoot指標(biāo)監(jiān)控的實(shí)現(xiàn)
本文主要介紹了SpringBoot指標(biāo)監(jiān)控的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Java JVM原理與調(diào)優(yōu)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫(xiě),JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī),是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。下面通過(guò)本文給大家介紹jvm原理與調(diào)優(yōu)相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧2017-04-04java?讀寫(xiě)鎖的使用及它的優(yōu)點(diǎn)
這篇文章主要介紹了java?讀寫(xiě)鎖的使用及它的優(yōu)點(diǎn),讀寫(xiě)鎖的特點(diǎn)就是是讀讀不互斥、讀寫(xiě)互斥、寫(xiě)寫(xiě)互斥,下面具體使用分享需要的小伙伴可以參考一下2022-05-05