J.U.C之ReentrantLock 可重入鎖

* A reentrant mutual exclusion {@link Lock} with the same basic
* behavior and semantics as the implicit monitor lock accessed using
* {@code synchronized} methods and statements, but with extended
* capabilities.

一個可重入的互斥鎖,它與使用synchronized的方法和語句來進行隱式鎖訪問的方式具備相同的基本行爲和語義,可是同時具備一些擴展功能。java

* <p>The constructor for this class accepts an optional
* <em>fairness</em> parameter.  When set {@code true}, under
* contention, locks favor granting access to the longest-waiting
* thread.  Otherwise this lock does not guarantee any particular
* access order.  Programs using fair locks accessed by many threads
* may display lower overall throughput (i.e., are slower; often much
* slower) than those using the default setting, but have smaller
* variances in times to obtain locks and guarantee lack of
* starvation.

ReentrantLock構造方法接收一個可選的公平參數。當設置爲true時,它是公平鎖,這時鎖會將訪問權授予等待時間最長的線程。不然該鎖將沒法保證線程獲取鎖的訪問順序。公平鎖與非公平鎖相比,使用公平鎖的程序會有較低的吞吐量,但使用公平鎖能有效減小線程飢餓的發生。ui

使用建議:通常推薦的使用方式就是 lock()後緊跟try塊,例如:this

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

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

1、源碼解析

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

/**
 * Sync object for non-fair locks
 */
static final class NonfairSync extends Sync

/**
 * Sync object for fair locks
 */
static final class FairSync extends Sync

以上爲ReentrantLock提供的3個靜態內部類,其中Sync類繼承自AbstractQueuedSynchronizer(抽象隊列同步器),而NonfairSync和FairSync爲Sync類的兩個實現,分別應用於非公平鎖和公平鎖的場景,而公平鎖和非公平鎖在釋放鎖的狀況都是同樣的,只是在獲取鎖時,公平鎖會讓等待最久的線程優先獲取到鎖,而非公平鎖在獲取鎖時各線程機會均等,這樣也就致使會出現飢餓現象產生.線程

static final class FairSync extends Sync
    final void lock() {acquire(1);}
static final class NonfairSync extends Sync
{
    final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
}

以上爲公平鎖和非公平鎖調用lock()的源碼,其中的compareAndSetState,setExclusiveOwnerThread和acquire 均來自AQS中,有次能夠看出非公平鎖在lock時就會去嘗試1次去獲取鎖,獲取到了就返回,若是獲取不到,則跟公平鎖同樣,調用acquire(arg)再次嘗試獲取鎖,說白了,非公平鎖比公平鎖多1次搶佔鎖的動做。而在搶佔動做中,非公平鎖是直接嘗試搶佔,而公平鎖會先判斷是否位於頭結點來決定是否搶佔。code

非公平鎖獲取鎖源碼繼承

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 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、使用場景

場景1 防止重複執行ci

ReentrantLock lock = new ReentrantLock();

if(lock.tryLock()){//若是已經被lock,則直接放回false,不會等待,達到忽略的效果
    try
    {

    }finally {
        lock.unlock();
    }
}

場景2 串行執行(同步執行,相似synchronized)get

try
{
    lock.lock();

    
}finally {
    lock.unlock();
}

場景3 超時等待同步

try{
    if(lock.tryLock(5, TimeUnit.SECONDS)){
        try
        {

        }finally {
            lock.unlock();
        }
    }
}catch (InterruptedException ex){
    ex.printStackTrace();
}

場景4 響應中斷

try {
    lock.lockInterruptibly();


} catch (InterruptedException ex) {
  ex.printStackTrace();
} finally {
    lock.unlock();
}
相關文章
相關標籤/搜索