• 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();
    }
    
  • 相关阅读:
    PowerShell里的数组
    题解 cf gym 103261 D FFT Algorithm
    欧拉筛求积性函数的一般形式
    题解 LOJ 6053
    题解 SP34112 UDIVSUM
    题解 luogu P5162 WD与积木
    Java 关闭流同步输入输出
    题解 luogu P6620 [省选联考 2020 A 卷] 组合数问题
    hdu 6588 题解
    题解 cf gym 102979 E Expected Distance
  • 原文地址:https://www.cnblogs.com/oxf5deb3/p/13703154.html
Copyright © 2020-2023  润新知