摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會(huì)被掛起或者是自旋,然后當(dāng)線程釋放鎖后,線程再被喚醒,以此類推,按照申請(qǐng)鎖的先后順序來(lái)。
Node exclusive lock(獨(dú)占鎖) ReentrantLock
ReentrantLock實(shí)現(xiàn)了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。
公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會(huì)被掛起或者是自旋,然后當(dāng)線程A釋放鎖后,線程B再被喚醒,以此類推,按照申請(qǐng)鎖的先后順序來(lái)。
非公平鎖: 線程A占用鎖,B等待,于此同時(shí)C請(qǐng)求鎖,由于B線程被喚醒需要時(shí)間,所以C有可能在B被喚醒錢就釋放鎖,以此類推,按照鎖空閑時(shí)申請(qǐng)鎖的線程為優(yōu)先。
NonfairSync世界應(yīng)該是公平公正的不是嗎?好了,別白日做夢(mèng)了,由于線程的喚醒是一個(gè)比較耗時(shí)的操作(切換線程上下文,調(diào)用OS等)如果線程持有鎖的時(shí)間很長(zhǎng),那么公平鎖就比較有優(yōu)勢(shì)
NonfairSync中l(wèi)ock的實(shí)現(xiàn)如下:
final void lock() { // CAS操作設(shè)置AbstractQueuedSynchronizer中的volatile int state // 如果設(shè)置成功將現(xiàn)有的線程setExclusiveOwnerThread if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else // CAS失敗了就調(diào)用acquire()方法 acquire(1); }
acquire方法由AbstractQueuedSynchronizer提供
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
tryAcquire在AbstractQueuedSynchronizer中是一個(gè)protected方法并且沒有給出實(shí)現(xiàn),可見是希望由它的子類去擴(kuò)展
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
回去再看NonfairSync中tryAcquire的實(shí)現(xiàn)
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 獲取同步state int c = getState(); // 這個(gè)判斷很有意思,由于調(diào)用這個(gè)方式是第一次嘗試CAS失敗才會(huì)進(jìn)入該方法 // 這里重新再判斷一次同步state,可以避免之前的線程已經(jīng)釋放lock,而繼續(xù)將 // 該線程放入等待隊(duì)列的情況,和lock()的第一段代碼含義相同設(shè)置同步state if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 接下來(lái)判斷是否是同一個(gè)線程,這個(gè)判斷是因?yàn)镽eentrantLock是可重入的lock else if (current == getExclusiveOwnerThread()) { // 將state++,這里的lock的獲取就是通過(guò)同步state的值來(lái)控制的 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
這段代碼大概的意思就是如果還沒有線程占用鎖就設(shè)置state為1,如果是已經(jīng)占用該鎖的線程再次訪問(wèn)就累計(jì)state的值,返回true,如果已經(jīng)被占用返回false
回過(guò)頭來(lái)繼續(xù)看acquire,!tryAcquire(arg)意味著獲取鎖失敗,然后執(zhí)行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
進(jìn)入addWaiter方法
/** * 1. 初始化: 如果tail和head沒有被初始化,那么創(chuàng)建一個(gè)node并且指向它 * +------+ * | Node | <---- tail, head * |(Head)| * +------+ * * 2. 添加新的節(jié)點(diǎn)進(jìn)入隊(duì)列 * +------+ prev +------+ * head ----> | Node | <---- | Node | <---- tail * |(Head)| ----> |Thread| * +------+ next +------+ */ private Node addWaiter(Node mode) { // 創(chuàng)建一個(gè)node使用EXCLUSIVE模式 Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; // 如果隊(duì)列不是null(已經(jīng)有線程再等待鎖)那么將該新增的node加入隊(duì)列 if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // 如果上述代碼沒有成功,這里是使用自旋的方式繼續(xù)加入等待隊(duì)列 enq(node); // 入隊(duì)成功后返回新增node節(jié)點(diǎn) return node; } // 將新的node節(jié)點(diǎn)入隊(duì)并返回之前的tail節(jié)點(diǎn) private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize if (compareAndSetHead(new Node())) tail = head; } else { // 典型的入隊(duì)操作將tail指向新增的node node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
然后再看acquireQueued,此時(shí)的node參數(shù)是之前我們分析的新增入隊(duì)列的node節(jié)點(diǎn)
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { // 返回node的前一個(gè)節(jié)點(diǎn) final Node p = node.predecessor(); /** * 如果該新增node的prev-node是head-node.如下圖這種狀態(tài) * 也就是說(shuō)在等待隊(duì)列中只有一個(gè)node,Head-node不包含在 * 內(nèi),并且調(diào)用tryAcquire方法成功(即成功的設(shè)置了同步state) * * * +------+ prev +------+ * head ----> | Node | <---- | Node | <---- tail * |(Head)| ----> |Thread| * +------+ next +------+ * * 那么將head指向改node,原來(lái)的head的next節(jié)點(diǎn)為null * * +-------------+ * head ----> | Node | <---- tail * |Thread = null| * +-------------+ * */ if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } // if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
接下來(lái)是shouldParkAfterFailedAcquire,顧名思義該方法返回是否在獲取lock失敗后堵塞線程,該方法會(huì)忽略并移出隊(duì)列中node.waitStatus = CANCELLED的node
/** * 該方的參數(shù)是 pred是Thread-A所在的node,node是Thread-B所在的node * 這個(gè)必須得理解 * * +------+ prev +--------------+ prev +--------+ * head ----> | Node | <---- | Node | <---- | Node |<---- tail * |(Head)| ----> |Thread-A | ----> |Thread-B| * +------+ next |waitStatus = 0| | | * +--------------+ +--------+ * * +------+ prev +---------------+ prev +--------+ * head ----> | Node | <---- | Node | <---- | Node |<---- tail * |(Head)| ----> |Thread-A | ----> |Thread-B| * +------+ next |waitStatus = -1| | | * +---------------+ +--------+ * * static final int CANCELLED = 1; * static final int SIGNAL = -1; * static final int CONDITION = -2; * static final int PROPAGATE = -3; * * 同時(shí)這個(gè)方法又分為2步(似乎整個(gè)AQS中都充斥著延遲初始化的概念) * 1. 初始化: 設(shè)置形參pred的waitStatus屬性為Node.SIGNAL * 2. 由于調(diào)用shouldParkAfterFailedAcquire()方法的acquireQueued()方法 * 還在自旋中,所以該方法會(huì)被調(diào)用第2次,這次才真正返回true,如果waitStatus * 被設(shè)置成CANCELLED,那么會(huì)忽略等待隊(duì)列中的這些node * */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { /* * waitStatus must be 0 or PROPAGATE. Indicate that we * need a signal, but don"t park yet. Caller will need to * retry to make sure it cannot acquire before parking. */ // 這里就是初始化的代碼,設(shè)置形參pred的waitStatus屬性為Node.SIGNAL compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
parkAndCheckInterrupt()方法,使用LockSupport堵塞當(dāng)前node對(duì)應(yīng)的thread,并返回中斷標(biāo)識(shí),當(dāng)這個(gè)方法被調(diào)用時(shí)才真正的意味著lock.lock()方法完成了它的使命
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }補(bǔ)充說(shuō)明 unsafe類
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/76293.html
摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會(huì)被掛起或者是自旋,然后當(dāng)線程釋放鎖后,線程再被喚醒,以此類推,按照申請(qǐng)鎖的先后順序來(lái)。 Node exclusive lock(獨(dú)占鎖) ReentrantLock ReentrantLock實(shí)現(xiàn)了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會(huì)被掛起或...
摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會(huì)被掛起或者是自旋,然后當(dāng)線程釋放鎖后,線程再被喚醒,以此類推,按照申請(qǐng)鎖的先后順序來(lái)。 Node exclusive lock(獨(dú)占鎖) ReentrantLock ReentrantLock實(shí)現(xiàn)了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會(huì)被掛起或...
摘要:公平鎖線程占用鎖,等待,然后依次獲取鎖,其中會(huì)被掛起或者是自旋,然后當(dāng)線程釋放鎖后,線程再被喚醒,以此類推,按照申請(qǐng)鎖的先后順序來(lái)。 Node exclusive lock(獨(dú)占鎖) ReentrantLock ReentrantLock實(shí)現(xiàn)了公平鎖與非公平鎖,公平鎖提供順序獲取鎖的方式,而非公平鎖提供搶占式獲取鎖的方式。公平鎖: 線程A占用鎖,B等待,然后依次獲取鎖,其中B會(huì)被掛起或...
摘要:實(shí)現(xiàn)原理是通過(guò)基于單鏈表的條件隊(duì)列來(lái)管理等待線程的。中斷在轉(zhuǎn)移到同步隊(duì)列期間或之后發(fā)生,此時(shí)表明有線程正在調(diào)用轉(zhuǎn)移節(jié)點(diǎn)。在該種中斷模式下,再次設(shè)置線程的中斷狀態(tài)。 1. 簡(jiǎn)介 Condition是一個(gè)接口,AbstractQueuedSynchronizer 中的ConditionObject內(nèi)部類實(shí)現(xiàn)了這個(gè)接口。Condition聲明了一組等待/通知的方法,這些方法的功能與Objec...
摘要:實(shí)現(xiàn)原理是通過(guò)基于單鏈表的條件隊(duì)列來(lái)管理等待線程的。中斷在轉(zhuǎn)移到同步隊(duì)列期間或之后發(fā)生,此時(shí)表明有線程正在調(diào)用轉(zhuǎn)移節(jié)點(diǎn)。在該種中斷模式下,再次設(shè)置線程的中斷狀態(tài)。 1. 簡(jiǎn)介 Condition是一個(gè)接口,AbstractQueuedSynchronizer 中的ConditionObject內(nèi)部類實(shí)現(xiàn)了這個(gè)接口。Condition聲明了一組等待/通知的方法,這些方法的功能與Objec...
閱讀 630·2023-04-26 01:53
閱讀 2754·2021-11-17 17:00
閱讀 2891·2021-09-04 16:40
閱讀 1992·2021-09-02 15:41
閱讀 839·2019-08-26 11:34
閱讀 1228·2019-08-26 10:16
閱讀 1340·2019-08-23 17:51
閱讀 825·2019-08-23 16:50