深入理解ReentrantLock

在Java中通常實(shí)現(xiàn)鎖有兩種方式宾添,一種是synchronized關(guān)鍵字船惨,另一種是Lock。二者其實(shí)并沒(méi)有什么必然聯(lián)系辞槐,但是各有各的特點(diǎn)掷漱,在使用中可以進(jìn)行取舍的使用。首先我們先對(duì)比下兩者榄檬。

實(shí)現(xiàn):#####

首先最大的不同:synchronized是基于JVM層面實(shí)現(xiàn)的卜范,而Lock是基于JDK層面實(shí)現(xiàn)的。曾經(jīng)反復(fù)的找過(guò)synchronized的實(shí)現(xiàn)鹿榜,可惜最終無(wú)果海雪。但Lock卻是基于JDK實(shí)現(xiàn)的锦爵,我們可以通過(guò)閱讀JDK的源碼來(lái)理解Lock的實(shí)現(xiàn)。

使用:#####

對(duì)于使用者的直觀體驗(yàn)上Lock是比較復(fù)雜的奥裸,需要lock和realse险掀,如果忘記釋放鎖就會(huì)產(chǎn)生死鎖的問(wèn)題,所以湾宙,通常需要在finally中進(jìn)行鎖的釋放樟氢。但是synchronized的使用十分簡(jiǎn)單,只需要對(duì)自己的方法或者關(guān)注的同步對(duì)象或類使用synchronized關(guān)鍵字即可侠鳄。但是對(duì)于鎖的粒度控制比較粗埠啃,同時(shí)對(duì)于實(shí)現(xiàn)一些鎖的狀態(tài)的轉(zhuǎn)移比較困難。例如:

特點(diǎn):#####
tips synchronized Lock
鎖獲取超時(shí) 不支持 支持
獲取鎖響應(yīng)中斷 不支持 支持
優(yōu)化:#####

在JDK1.5之后synchronized引入了偏向鎖伟恶,輕量級(jí)鎖和重量級(jí)鎖碴开,從而大大的提高了synchronized的性能,同時(shí)對(duì)于synchronized的優(yōu)化也在繼續(xù)進(jìn)行博秫。期待有一天能更簡(jiǎn)單的使用java的鎖潦牛。

在以前不了解Lock的時(shí)候,感覺(jué)Lock使用實(shí)在是太復(fù)雜挡育,但是了解了它的實(shí)現(xiàn)之后就被深深吸引了巴碗。

Lock的實(shí)現(xiàn)主要有ReentrantLock、ReadLock和WriteLock即寒,后兩者接觸的不多良价,所以簡(jiǎn)單分析一下ReentrantLock的實(shí)現(xiàn)和運(yùn)行機(jī)制。

ReentrantLock類在java.util.concurrent.locks包中蒿叠,它的上一級(jí)的包java.util.concurrent主要是常用的并發(fā)控制類.

Paste_Image.png

下面是ReentrantLock的UML圖,從圖中可以看出蚣常,ReentrantLock實(shí)現(xiàn)Lock接口市咽,在ReentrantLock中引用了AbstractQueuedSynchronizer的子類,所有的同步操作都是依靠AbstractQueuedSynchronizer(隊(duì)列同步器)實(shí)現(xiàn)抵蚊。

Paste_Image.png

研究一個(gè)類施绎,需要從一個(gè)類的靜態(tài)域,靜態(tài)類贞绳,靜態(tài)方法和成員變量開(kāi)始谷醉。

 private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is
         * implemented in subclasses, but both need nonfair
         * try for trylock method.
         */
        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;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes this lock instance from a stream.
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

從上面的代碼可以看出來(lái)首先ReentrantLock是可序列化的,其次是ReentrantLock里有一個(gè)對(duì)AbstractQueuedSynchronizer的引用冈闭。

看完了成員變量和靜態(tài)域俱尼,我們需要了解下構(gòu)造方法:

/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

從上面代碼可以看出,ReentrantLock支持兩種鎖模式萎攒,公平鎖和非公平鎖遇八。默認(rèn)的實(shí)現(xiàn)是非公平的矛绘。公平和非公平鎖的實(shí)現(xiàn)如下:

 /**
     * Sync object for non-fair locks
     */
    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() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    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;
        }
    }

AbstractQueuedSynchronizer 是一個(gè)抽象類,所以在使用這個(gè)同步器的時(shí)候刃永,需要通過(guò)自己實(shí)現(xiàn)預(yù)期的邏輯货矮,Sync、FairSync和NonfairSync都是ReentrantLock為了實(shí)現(xiàn)自己的需求而實(shí)現(xiàn)的內(nèi)部類斯够,之所以做成內(nèi)部類囚玫,我認(rèn)為是只在ReentrantLock使用上述幾個(gè)類,在外部沒(méi)有使用到读规。
我們著重關(guān)注默認(rèn)的非公平鎖的實(shí)現(xiàn):
在ReentrantLock調(diào)用lock()的時(shí)候抓督,調(diào)用的是下面的代碼:

 /**
     * Acquires the lock.
     *
     * <p>Acquires the lock if it is not held by another thread and returns
     * immediately, setting the lock hold count to one.
     *
     * <p>If the current thread already holds the lock then the hold
     * count is incremented by one and the method returns immediately.
     *
     * <p>If the lock is held by another thread then the
     * current thread becomes disabled for thread scheduling
     * purposes and lies dormant until the lock has been acquired,
     * at which time the lock hold count is set to one.
     */
    public void lock() {
        sync.lock();
    }

sync的實(shí)現(xiàn)是NonfairSync,所以調(diào)用的是NonfairSync的lock方法:

/**
     * Sync object for non-fair locks
     * tips:調(diào)用Lock的時(shí)候掖桦,嘗試獲取鎖本昏,這里采用的CAS去嘗試獲取鎖,如果獲取鎖成功
     *       那么枪汪,當(dāng)前線程獲取到鎖涌穆,如果失敗,調(diào)用acquire處理雀久。
     * 
     */
    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() {
            
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

接下來(lái)看看compareAndSetState方法是怎么進(jìn)行鎖的獲取操作的:

/**
     * Atomically sets synchronization state to the given updated
     * value if the current state value equals the expected value.
     * This operation has memory semantics of a <tt>volatile</tt> read
     * and write.
     *
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that the actual
     *         value was not equal to the expected value.
     *         
     * tips: 1.compareAndSetState的實(shí)現(xiàn)主要是通過(guò)Unsafe類實(shí)現(xiàn)的宿稀。
     *       2.之所以命名為Unsafe,是因?yàn)檫@個(gè)類對(duì)于JVM來(lái)說(shuō)是不安全的赖捌,我們平時(shí)也是使用不了這個(gè)類的祝沸。
     *       3.Unsafe類內(nèi)封裝了一些可以直接操作指定內(nèi)存位置的接口,是不是感覺(jué)和C有點(diǎn)像了越庇?
     *       4.Unsafe類封裝了CAS操作罩锐,來(lái)達(dá)到樂(lè)觀的鎖的爭(zhēng)搶的效果
     */
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

主要的說(shuō)明都在方法的注釋中,接下來(lái)簡(jiǎn)單的看一下compareAndSwapInt的實(shí)現(xiàn):

/**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

一個(gè)native方法卤唉,沮喪.....但是從注釋看意思是涩惑,以CAS的方式將制定字段設(shè)置為指定的值。同時(shí)我們也明白了這個(gè)方法可能是用java實(shí)現(xiàn)不了桑驱,只能依賴JVm底層的C代碼實(shí)現(xiàn)竭恬。下面看看操作的stateOffset:

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long stateOffset;
    private static final long headOffset;
    private static final long tailOffset;
    private static final long waitStatusOffset;
    private static final long nextOffset;

    static {
        try {
            //這個(gè)方法很有意思,主要的意思是獲取AbstractQueuedSynchronizer的state成員的偏移量
            //通過(guò)這個(gè)偏移量來(lái)更新state成員熬的,另外state是volatile的來(lái)保證可見(jiàn)性痊硕。
            stateOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
            waitStatusOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("waitStatus"));
            nextOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("next"));

        } catch (Exception ex) { throw new Error(ex); }
    }

stateOffset 是AbstractQueuedSynchronizer內(nèi)部定義的一個(gè)狀態(tài)量,AbstractQueuedSynchronizer是線程的競(jìng)態(tài)條件押框,所以只要某一個(gè)線程CAS改變狀態(tài)成功岔绸,同時(shí)在沒(méi)有釋放的情況下,其他線程必然失敗(對(duì)于Unsafe類還不是很熟悉亭螟,后面還需要系統(tǒng)的學(xué)習(xí))挡鞍。
對(duì)于競(jìng)爭(zhēng)成功的線程會(huì)調(diào)用setExclusiveOwnerThread方法:

/**
     * The current owner of exclusive mode synchronization.
     */
    private transient Thread exclusiveOwnerThread;

    /**
     * Sets the thread that currently owns exclusive access. A
     * <tt>null</tt> argument indicates that no thread owns access.
     * This method does not otherwise impose any synchronization or
     * <tt>volatile</tt> field accesses.
     */
    protected final void setExclusiveOwnerThread(Thread t) {
        exclusiveOwnerThread = t;
    }

這個(gè)實(shí)現(xiàn)是比較簡(jiǎn)單的,只是獲取當(dāng)前線程的引用预烙,令A(yù)bstractOwnableSynchronizer中的exclusiveOwnerThread引用到當(dāng)前線程墨微。
對(duì)于競(jìng)爭(zhēng)失敗的線程,會(huì)調(diào)用acquire方法扁掸,這個(gè)方法也是ReentrantLock設(shè)計(jì)的精華之處:

/**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     * tips:此處主要是處理沒(méi)有獲取到鎖的線程
     *   tryAcquire:重新進(jìn)行一次鎖獲取和進(jìn)行鎖重入的處理翘县。
     *      addWaiter:將線程添加到等待隊(duì)列中。
     *   acquireQueued:自旋獲取鎖谴分。      
     *      selfInterrupt:中斷線程锈麸。
     *      三個(gè)條件的關(guān)系為and,如果 acquireQueued返回true,那么線程被中斷selfInterrupt會(huì)中斷線程
     */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

AbstractQueuedSynchronizer為抽象方法牺蹄,調(diào)用tryAcquire時(shí)忘伞,調(diào)用的為NonfairSync的tryAcquire。

 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
       /**
         * Performs non-fair tryLock.  tryAcquire is
         * implemented in subclasses, but both need nonfair
         * try for trylock method.
         */
        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;
        }

nonfairTryAcquire方法主要是做重入鎖的實(shí)現(xiàn)沙兰,synchronized本身支持鎖的重入氓奈,而ReentrantLock則是通過(guò)此處實(shí)現(xiàn)。在鎖狀態(tài)為0時(shí)鼎天,重新嘗試獲取鎖舀奶。如果已經(jīng)被占用,那么做一次是否當(dāng)前線程為占用鎖的線程的判斷斋射,如果是一樣的那么進(jìn)行計(jì)數(shù)育勺,當(dāng)然在鎖的relase過(guò)程中會(huì)進(jìn)行遞減,保證鎖的正常釋放罗岖。
如果沒(méi)有重新獲取到鎖或者鎖的占用線程和當(dāng)前線程是一個(gè)線程涧至,方法返回false。那么把線程添加到等待隊(duì)列中桑包,調(diào)用addWaiter:

   /**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
/**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

這里主要是用當(dāng)前線程構(gòu)建一個(gè)Node的等待隊(duì)列雙向鏈表化借,這里addWaiter中和enq中的部分邏輯是重復(fù)的,個(gè)人感覺(jué)可能是如果能一次成功就避免了enq中的死循環(huán)捡多。因?yàn)閠ail節(jié)點(diǎn)是volatile的同時(shí)node也是不會(huì)發(fā)生競(jìng)爭(zhēng)的所以node.prev = pred;是安全的。但是tail的next是不斷競(jìng)爭(zhēng)的铐炫,所以利用compareAndSetTail保證操作的串行化垒手。接下來(lái)調(diào)用acquireQueued方法:

/**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                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);
        }
    }

此處是做Node節(jié)點(diǎn)線程的自旋過(guò)程,自旋過(guò)程主要檢查當(dāng)前節(jié)點(diǎn)是不是head節(jié)點(diǎn)的next節(jié)點(diǎn)倒信,如果是科贬,則嘗試獲取鎖,如果獲取成功,那么釋放當(dāng)前節(jié)點(diǎn)榜掌,同時(shí)返回优妙。至此一個(gè)非公平鎖的鎖獲取過(guò)程結(jié)束。
如果這里一直不斷的循環(huán)檢查憎账,其實(shí)是很耗費(fèi)性能的套硼,JDK的實(shí)現(xiàn)肯定不會(huì)這么“弱智”,所以有了shouldParkAfterFailedAcquire和parkAndCheckInterrupt胞皱,這兩個(gè)方法就實(shí)現(xiàn)了線程的等待從而避免無(wú)限的輪詢:

 /**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    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.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

首先邪意,檢查一下當(dāng)前Node的前置節(jié)點(diǎn)pred是否是SIGNAL,如果是SIGNAL反砌,那么證明前置Node的線程已經(jīng)Park了雾鬼,如果waitStatus>0,那么當(dāng)前節(jié)點(diǎn)已經(jīng)Concel或者中斷。那么不斷調(diào)整當(dāng)前節(jié)點(diǎn)的前置節(jié)點(diǎn)宴树,將已經(jīng)Concel的和已經(jīng)中斷的線程移除隊(duì)列策菜。如果waitStatus<0,那么設(shè)置waitStatus為SIGNAL,因?yàn)檎{(diào)用shouldParkAfterFailedAcquire的方法為死循環(huán)調(diào)用酒贬,所以終將返回true又憨。接下來(lái)看parkAndCheckInterrupt方法,當(dāng)shouldParkAfterFailedAcquire返回True的時(shí)候執(zhí)行parkAndCheckInterrupt方法:

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

此方法比較簡(jiǎn)單同衣,其實(shí)就是使當(dāng)前的線程park竟块,即暫停了線程的輪詢。當(dāng)Unlock時(shí)會(huì)做后續(xù)節(jié)點(diǎn)的Unpark喚醒線程繼續(xù)爭(zhēng)搶鎖耐齐。
接下來(lái)看一下鎖的釋放過(guò)程浪秘,鎖釋放主要是通過(guò)unlock方法實(shí)現(xiàn):

 /**
     * Attempts to release this lock.
     *
     * <p>If the current thread is the holder of this lock then the hold
     * count is decremented.  If the hold count is now zero then the lock
     * is released.  If the current thread is not the holder of this
     * lock then {@link IllegalMonitorStateException} is thrown.
     *
     * @throws IllegalMonitorStateException if the current thread does not
     *         hold this lock
     */
    public void unlock() {
        sync.release(1);
    }

主要是調(diào)用AbstractQueuedSynchronizer同步器的release方法:

    /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease方法為ReentrantLock中的Sync的tryRelease方法:

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

tryRelease方法主要是做了一個(gè)釋放鎖的過(guò)程,將同步狀態(tài)state -1埠况,直到減到0為止耸携,這主要是兼容重入鎖設(shè)計(jì)的,同時(shí)setExclusiveOwnerThread(null)清除當(dāng)前占用的線程辕翰。這些head節(jié)點(diǎn)后的線程和新進(jìn)的線程就可以開(kāi)始爭(zhēng)搶夺衍。這里需要注意的是對(duì)于同步隊(duì)列中的線程來(lái)說(shuō)在setState(c)瓤鼻,且c為0的時(shí)候酵紫,同步隊(duì)列中的線程是沒(méi)有競(jìng)爭(zhēng)鎖的,因?yàn)榫€程被park了還沒(méi)有喚醒惠啄。但是此時(shí)對(duì)于新進(jìn)入的線程是有機(jī)會(huì)獲取到鎖的壁榕。
下面代碼是進(jìn)行線程的喚醒:

 Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;

因?yàn)樵趕etState(c)釋放了鎖之后矛紫,是沒(méi)有線程競(jìng)爭(zhēng)的,所以head是當(dāng)前的head節(jié)點(diǎn)牌里,先檢查當(dāng)前的Node是否合法颊咬,如果合法則unpark it。開(kāi)始鎖的獲取。就回到了上面的for循環(huán)執(zhí)行獲取鎖邏輯:

Paste_Image.png

至此鎖的釋放就結(jié)束了喳篇,可以看到ReentrantLock是一個(gè)不斷的循環(huán)的狀態(tài)模型敞临,里面有很多東西值得我們學(xué)習(xí)和思考。

ReentrantLock具有公平和非公平兩種模式麸澜,也各有優(yōu)缺點(diǎn):
公平鎖是嚴(yán)格的以FIFO的方式進(jìn)行鎖的競(jìng)爭(zhēng)挺尿,但是非公平鎖是無(wú)序的鎖競(jìng)爭(zhēng),剛釋放鎖的線程很大程度上能比較快的獲取到鎖痰憎,隊(duì)列中的線程只能等待票髓,所以非公平鎖可能會(huì)有“饑餓”的問(wèn)題。但是重復(fù)的鎖獲取能減小線程之間的切換铣耘,而公平鎖則是嚴(yán)格的線程切換洽沟,這樣對(duì)操作系統(tǒng)的影響是比較大的,所以非公平鎖的吞吐量是大于公平鎖的蜗细,這也是為什么JDK將非公平鎖作為默認(rèn)的實(shí)現(xiàn)裆操。

最后:#####

關(guān)于并發(fā)和Lock還有很多的點(diǎn)還是比較模糊,我也會(huì)繼續(xù)學(xué)習(xí)炉媒,繼續(xù)總結(jié)踪区,如果文章中有什么問(wèn)題,還請(qǐng)各位看客及時(shí)指出吊骤,共同學(xué)習(xí)缎岗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市白粉,隨后出現(xiàn)的幾起案子传泊,更是在濱河造成了極大的恐慌,老刑警劉巖鸭巴,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眷细,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鹃祖,警方通過(guò)查閱死者的電腦和手機(jī)溪椎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恬口,“玉大人校读,你說(shuō)我怎么就攤上這事∽婺埽” “怎么了地熄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芯杀。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么揭厚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任却特,我火速辦了婚禮,結(jié)果婚禮上筛圆,老公的妹妹穿的比我還像新娘裂明。我一直安慰自己,他們只是感情好太援,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布闽晦。 她就那樣靜靜地躺著,像睡著了一般提岔。 火紅的嫁衣襯著肌膚如雪仙蛉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天碱蒙,我揣著相機(jī)與錄音荠瘪,去河邊找鬼。 笑死赛惩,一個(gè)胖子當(dāng)著我的面吹牛哀墓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播喷兼,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼篮绰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了季惯?” 一聲冷哼從身側(cè)響起吠各,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎星瘾,沒(méi)想到半個(gè)月后走孽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琳状,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年磕瓷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片念逞。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡困食,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出翎承,到底是詐尸還是另有隱情硕盹,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布叨咖,位于F島的核電站瘩例,受9級(jí)特大地震影響啊胶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垛贤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一焰坪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧聘惦,春花似錦某饰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至禀酱,卻和暖如春炬守,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背比勉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工劳较, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浩聋。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓观蜗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親衣洁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子墓捻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件坊夫,多個(gè)...
    一字馬胡閱讀 44,146評(píng)論 1 32
  • 前言 上一篇文章《基于CAS操作的Java非阻塞同步機(jī)制》 分析了非同步阻塞機(jī)制的實(shí)現(xiàn)原理砖第,本篇將分析一種以非同步...
    Mars_M閱讀 4,798評(píng)論 5 9
  • 第三章 Java內(nèi)存模型 3.1 Java內(nèi)存模型的基礎(chǔ) 通信在共享內(nèi)存的模型里,通過(guò)寫-讀內(nèi)存中的公共狀態(tài)進(jìn)行隱...
    澤毛閱讀 4,347評(píng)論 2 22
  • 近來(lái)決定好好學(xué)習(xí)一下設(shè)計(jì)模式环凿,為以后編寫開(kāi)源框架之路打打基礎(chǔ)梧兼。 1)里氏代換原則 ---- 子類型必須能夠替換掉它...
    wdming閱讀 260評(píng)論 0 0
  • 來(lái)世有何歡? 品盡人間味智听; 歸去無(wú)所戚羽杰, 一縷青煙飛。
    王文英wwy閱讀 497評(píng)論 0 0