併發編程之ReentrantLock解析

是一種可重入同步互斥鎖,其行爲和語義和synchronized相同,但是對其進行了延申和升級,比如支持超時獲取與公平策略,能響應線程中斷,能夠知道是否獲取到了鎖,更加靈活,效率更低.公平策略會降低吞吐量,但是能有效避免線程飢餓,在爭用情況下,公平策略鎖傾向於授予對等待時間最長的線程的訪問權,避免線程爭搶某個線程一直得不到CPU使用權.Lock不會像synchronized一樣,異常的時候自動釋放鎖,所以最佳實踐是,finally中釋放鎖,以便保證發生異常的時候鎖一定被釋放

源碼分析

java.lang.Object
java.util.concurrent.locks.ReentrantLock


public class ReentrantLock
extends Object
implements Lock, Serializable


//構造方法
  /**
     * 創造一個ReentrantLock實例
     * 這相當於使用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) {
    //FairSync和NonfairSync分別實現公平與非公平策略
        sync = fair ? new FairSync() : new NonfairSync();
    }


//重要方法

  * @return 當前線程對此鎖的保持數,如果當前線程不保持此鎖,則爲零
  * 
     */
    public int getHoldCount() {
        return sync.getHoldCount();
    }



 /**
     * 確定公平策略是否開啓,如果開啓返回true否則返回false
     *   
     * 默認是false
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }


 /**
     * 獲取鎖。
     * 如果鎖未被另一個線程持有,則獲取該鎖並立即返回,將鎖持有計數設置爲1。
     * 如果當前線程已經持有鎖,那麼持有計數將增加1,並且方法立即返回。
     * 如果鎖被另一個線程持有,則當前線程將因線程調度而禁用,並處於休眠狀態,直到獲得鎖爲止,此時鎖持有計數
     * 設置爲1。這裏解釋了Lock確實是一個重入鎖
     */
    public void lock() {
        sync.lock();
    }


 /**
     * 獲取鎖,除非當前線程被中斷。
     *
     * 如果鎖未被另一個線程持有,則獲取該鎖並立即返回,將鎖持有計數設置爲1。
     * 
     * 如果當前線程已經持有此鎖,則保持計數將增加1,並且方法將立即返回。
     *
     * 如果鎖被另一個線程持有,則當前線程將被禁用以進行線程調度
     *
     * 
     *在獲取鎖時被中斷,然後拋出InterruptedException並清除當前線程的中斷狀態。
     *在這個實現中,由於這個方法是一個顯式的中斷點,所以優先考慮響應中斷,而不是對鎖的正常或可重入獲取。
     *
     * @throws InterruptedException i如果獲取鎖被打斷
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }


 /**
     *嘗試獲取鎖,支持重入操作,
     *如果獲取成功返回true否則返回false,和lock()不同的是不會發生阻塞
     *公平策略對這個方法不起作用
     */
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }



/**
     *
     *在指定的時間內去獲取lock,如果獲取成功返回true否則返回false,這個方法支持公平策略,可重入,
     *響應中斷
     * @throws InterruptedException 如果被中斷
     * @throws NullPointerException 參數錯誤
     */
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }


 /**
     * 由鎖的持有者釋放鎖
     *
     * 釋放時計數器減一,計數器爲0才能釋放
     *
     * @throws IllegalMonitorStateException 非持有者試圖釋放鎖報錯
     *         
     */
    public void unlock() {
        sync.release(1);
    }

案例分析

ArrayBlockingQueue重要方法分析


  /**
     *將指定的元素插入到此隊列的尾部(如果立即可行且不會超過該隊列的容量
     *在成功時返回 true,如果此隊列已滿,則返回 false
     *
     * @throws NullPointerException 如果插入的元素爲空
     */
    public boolean offer(E e) {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        //加鎖
        lock.lock();
        try {
        //判斷隊列元素個數和數組的長度,如果相同隊列滿了,返回false
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
        //釋放鎖
            lock.unlock();
        }
    }


 /**
     * 將指定的元素加入隊列,如果隊列滿了發生阻塞
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public void put(E e) throws InterruptedException {
        Objects.requireNonNull(e);
        final ReentrantLock lock = this.lock;
        //加鎖
        lock.lockInterruptibly();
        try {
            while (count == items.length)
            //當隊列滿了就阻塞
                notFull.await();
                //有可用空間就插入元素
            enqueue(e);
        } finally {
        //釋放鎖
            lock.unlock();
        }
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章