天天看點

[多線程] Lock實作類 ReentrantLock 源碼淺析一 簡介:構造方法Lock 的方法ReentrantLock 的方法

文章目錄

  • 一 簡介:
  • 構造方法
    • NonfairSync 非公平鎖
    • FairSync 公平鎖
    • Sync
  • Lock 的方法
    • lock()
    • unlock()
    • newCondition()
    • tryLock()
    • lockInterruptibly()
  • ReentrantLock 的方法
    • isLocked()
    • isFair()
源碼來自 jdk1.6

一 簡介:

一個可重入的互斥鎖 Lock,它具有與使用 synchronized 方法和語句所通路的隐式螢幕鎖相同的一些基本行為和語義,但功能更強大。

ReentrantLock 将由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。當鎖沒有被另一個線程所擁有時,調用 lock 的線程将成功擷取該鎖并傳回。如果目前線程已經擁有該鎖,此方法将立即傳回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此情況是否發生。

此類的構造方法接受一個可選的公平 參數。當設定為 true 時,在多個線程的争用下,這些鎖傾向于将通路權授予等待時間最長的線程。否則此鎖将無法保證任何特定通路順序。與采用預設設定(使用不公平鎖)相比,使用公平鎖的程式在許多線程通路時表現為很低的總體吞吐量(即速度很慢,常常極其慢),但是在獲得鎖和保證鎖配置設定的均衡性時差異較小。不過要注意的是,公平鎖不能保證線程排程的公平性。是以,使用公平鎖的衆多線程中的一員可能獲得多倍的成功機會,這種情況發生在其他活動線程沒有被處理并且目前并未持有鎖時。還要注意的是,未定時的 tryLock 方法并沒有使用公平設定。因為即使其他線程正在等待,隻要該鎖是可用的,此方法就可以獲得成功。

建議總是 立即實踐,使用 lock 塊來調用 try,在之前/之後的構造中,最典型的代碼如下:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }
           

除了實作 Lock 接口,此類還定義了 isLocked 和 getLockQueueLength 方法,以及一些相關的 protected 通路方法,這些方法對檢測和監視可能很有用。

該類的序列化與内置鎖的行為方式相同:一個反序列化的鎖處于解除鎖定狀态,不管它被序列化時的狀态是怎樣的。

此鎖最多支援同一個線程發起的 2147483648 個遞歸鎖。試圖超過此限制會導緻由鎖方法抛出的 Error。

構造方法

public ReentrantLock() {
        sync = new NonfairSync();
    }
           
public ReentrantLock(boolean fair) {
        sync = (fair)? new FairSync() : new NonfairSync();
    }
           

NonfairSync 非公平鎖

同步對象以進行非公平鎖定

final static 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);
        }
    }
           

FairSync 公平鎖

同步對象以進行公平鎖定

final static 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 (isFirst(current) &&
                    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;
        }
    }
           

Sync

此鎖的同步控制基礎。 在下面轉換為公平和非公平版本。 使用AQS狀态表示鎖定的保持數。

static abstract 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
        }
    }
           

Lock 的方法

lock()

public void lock() {
        sync.lock();
    }
           

unlock()

public void unlock() {
        sync.release(1);
    }
           

newCondition()

public Condition newCondition() {
        return sync.newCondition();
    }
           

tryLock()

public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
           

tryLock(long, TimeUnit)

public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
           

lockInterruptibly()

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
           

ReentrantLock 的方法

isLocked()

public boolean isLocked() {
        return sync.isLocked();
    }
           

isFair()

public final boolean isFair() {
        return sync instanceof FairSync;
    }
           

持續更新…