ReentrantLock源碼分析--jdk1.8

JDK1.8

ArrayList源碼分析--jdk1.8
LinkedList源碼分析--jdk1.8
HashMap源碼分析--jdk1.8
AQS源碼分析--jdk1.8
ReentrantLock源碼分析--jdk1.8

ReentrantLock概述

  1. ReentrantLock是獨佔鎖。
  2. ReentrantLock分爲公平模式和非公平模式。
  3. ReentrantLock鎖可重入(重新插入)

ReentrantLock源碼分析

/**
 * @since 1.5
 * @author Doug Lea
 * 獨佔鎖 --默認使用非公平鎖模式
 * 可重入
 * 
 * synchronized鎖通過監視器Monitor來實現同步,monitorenter加鎖,monitorexit解鎖。
 * synchronized是可重如的非公平鎖
 * synchronized在jdk1.6進行優化,添加了偏向鎖、輕量級鎖、重量級鎖,關鍵字之鎖的升級(偏向鎖->輕量級鎖->重量級鎖)
 * 偏向鎖:當線程訪問同步塊時,會使用 CAS 將線程 ID 更新到鎖對象的 Mark Word 中,如果更新成功則獲得偏向鎖,並且之後每次進入這個對象鎖相關的同步塊時都不需要再次獲取鎖了。
 * 輕量級鎖:如果同步對象爲無鎖狀態時,直接嘗試CAS更新Mark Word添加鎖,如果成功,獲得鎖,失敗升級爲重量級鎖
 * 重量級鎖:是指當鎖是輕量級鎖時,當自旋的線程自旋了一定的次數後,還沒有獲取到鎖,就會進入阻塞狀態,該鎖升級爲重量級鎖,重量級鎖會使其他線程阻塞,性能降低。
 * 在使用 CAS 時,如果操作失敗,CAS 會自旋再次嘗試。由於自旋是需要消耗 CPU 資源的,所以如果長期自旋就白白浪費了 CPU。JDK1.6加入了適應性自旋:如果某個鎖自旋很少成功獲得,那麼下一次就會減少自旋。
 */
public class ReentrantLock implements Lock, java.io.Serializable {

    private static final long serialVersionUID = 7373984872572414699L;

    private final Sync sync;

    /**
     * Sync內部類,繼承AQS,實現獨佔鎖模式,作爲基礎內部類
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 加鎖
         */
        abstract void lock();

        /**
         * 判斷 reentranLock 狀態 是否被鎖住(state ?= 0)
         * <p>如果沒被鎖住嘗試 原子性上鎖 失敗返回false</>
         * <p>如果被鎖住 判斷是否是當前線程持有鎖(重入鎖的實現) 如果是 state + 1
         * (信號量  記錄該線程持有鎖的次數。 該線程每次釋放所 信號量 -1。 信號量爲零 代表 鎖被真正釋放)</>
         * <p>else 返回false</p>
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread(); //獲取到當前的線程
            int c = getState(); //獲取鎖的狀態
            if (c == 0) { //目前沒有人在佔有鎖 如果鎖已被經釋放 再次嘗試獲取鎖
                if (compareAndSetState(0, acquires)) { //直接嘗試把當前只設置成1,如果成功,把owner設置自己,並且退出
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { // 如果當前線程爲鎖的擁有者
                int nextc = c + acquires; //這裏就是重入鎖的概念,如果還是自己,則進行加1操作,因爲釋放和獲取一定要是對等的
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc); // 累加 state 的值  此段代碼 實現了重入鎖
                return true;
            }
            return false; //當前鎖被其他線程佔用,退出。
        }

        /**
         * 釋放鎖,默認releases傳1
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases; //獲取當前的鎖的狀態並且減1,因爲要釋放鎖
            if (Thread.currentThread() != getExclusiveOwnerThread()) //如果當前自己不是鎖的持有者,只有自己才能釋放鎖
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) { //釋放成功
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c); //重新設置成狀態
            return free;
        }

        /**
         * 如果當前線程獨佔着鎖,返回true
         */
        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();
        }

        /**
         * 返回鎖的擁有者的線程
         * 當前狀態爲0返回null,說明在等待中
         * 當前狀態不爲0返回當前線程
         */
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        /**
         * 當前線程佔着鎖返回 state,否則返回0
         */
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        /**
         * state狀態不爲0標識上鎖,爲0表示在等待,不上鎖
         */
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * 反序列化
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }
    /**
     * 構造方法,默認選擇非公平鎖
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * 構造方法,true公平鎖,false非公平鎖
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

ReentrantLock繼承和實現分析

ReentrantLock源碼分析--jdk1.8

   ReentrantLock implements Lock
   Sync extends AbstractQueuedSynchronizer
   1.ReentrantLock實現Lock接口,Lock接口定義了加鎖、條件隊列、解鎖、加鎖(中斷異常)
   2.Sync繼承AQS抽象類,實現了獨佔鎖,作爲基礎內部類

ReentrantLock源碼分析

1. FairSync公平鎖--內部類

/**
 * 公平鎖
 */
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;
    }
}

2. NonfairSync非公平鎖--內部類

/**
 * 非公平鎖的同步對象
 */
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); //嘗試以獨佔模式獲取鎖,如果失敗加入node節點到隊列中
    }
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}
/**
 * 是否有等待線程
 */
public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}
/**
 * 是否有等待線程
 */
public final boolean hasQueuedThreads() {
    return head != tail;
}

ReentrantLock總結

1)ReentrantLock是可重入的公平/非公平模式的獨佔鎖。
2)ReentrantLock公平鎖往往沒有非公平鎖的效率高,但是,並不是任何場景都是以TPS作爲唯一指標,公平鎖
能夠減少“飢餓”發生的概率,等待越久的請求越能夠得到優先滿足。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章