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的方法和语句来进行隐式锁访问的方式具有相同的基本行为和语义,但是同时具有一些扩展功能。

* <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时,它是公平锁,这时锁会将访问权授予等待时间最长的线程。否则该锁将无法保证线程获取锁的访问顺序。公平锁与非公平锁相比,使用公平锁的程序会有较低的吞吐量,但使用公平锁能有效减少线程饥饿的发生。

使用建议:一般推荐的使用方式就是 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()
     }
   }
 }}

一、源码解析

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次抢占锁的动作。而在抢占动作中,非公平锁是直接尝试抢占,而公平锁会先判断是否位于头结点来决定是否抢占。

非公平锁获取锁源码

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;
}

二、使用场景

场景1 防止重复执行

ReentrantLock lock = new ReentrantLock();

if(lock.tryLock()){//如果已经被lock,则直接放回false,不会等待,达到忽略的效果
    try
    {

    }finally {
        lock.unlock();
    }
}

场景2 串行执行(同步执行,类似synchronized)

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();
}
原文地址:https://www.cnblogs.com/oxf5deb3/p/13703154.html