ReentrantLock

ReentrantLock与synchronized齐名的经典java锁,十分常用。

ReentrantLock特性:

  • 可重入
  • 可通过构造参数设置时公平锁还是非公平锁
  • 需要明文释放锁,而synchronized是自动释放的
  • 可响应中断
  • 可在获取锁是设置超时时间
  • 通知队列

非公平锁原理

ReentrantLock本身没有直接实现锁,核心逻辑都交由AQS框架完成,内部核心类Sync即直接继承自AbstractQueuedSynchronizer类,
非公平锁模式:

  1. 某个线程加锁时会先尝试直接设置同步状态,成功就退出
  2. 第一步尝试失败后调用AbstractQueuedSynchronizer的acquire方法,
  3. AbstractQueuedSynchronizer的acquire方法中先调用子类tryAcquire方法,当等待队列为空或者队首节点持有线程就是当前线程则cas设置同步状态,
  4. 第三步也没加锁成功就加入CLH队列

公平锁模式:

  1. 直接调用AbstractQueuedSynchronizer的acquire方法
  2. AbstractQueuedSynchronizer的acquire方法中先调用子类tryAcquire方法,发现锁没线程持有就直接尝试cas设置同步状态,若是发现持有线程就是当前线程则将累计信号量,
  3. 第二步没获取到锁就加入CLH队列

对比两种模式可发现非公平模式下,一旦锁空闲了下来,新到来的线程可能会抢在等待队列中线程前面拿到锁,形成“插队”拿锁,还是直接插在了所有线程前面,但等待队列中的线程没有插队的机会,抱怨也没用,仍然是老老实实的按照顺序排队。

ReentrantLock成员变量

private final Sync sync;

ReentrantLock内部只有一个成员变量Sync,作为一个核心内部类,绝大部分方法都直接依赖这个类实现

ReentrantLock内部类

在这里插入图片描述
在这里插入图片描述
ReentrantLock内部共3个内部类,其中Sync是一个抽象方法类,继承自AbstractQueuedSynchronizer,类NonFairSync与FairSync均继承自Sync
类Sync关键方法有3个 分别是lock、nonfairTryAcquire、tryRelease,其中lock是抽象方法,放下面介绍,先看nonfairTryAcquire
nonfairTryAcquire如期单词意义,是用来获取同步信号量的,并且是非公平式的,也就是说排队的线程获取顺序不是严格的先到先得,而是谁抢到就是谁的

 //尝试获取释放状态
	protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            //不是当前线程则抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            //信号量恢复0代表持有当前锁的所有线程都已经释放完毕 
            if (c == 0) {
                free = true;
                //执行线程设置null
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
//非公平式尝试获取同步状态
	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()) {
               //锁已经被加锁过至少一次 并且加锁的是当前线程则信号量直接加acquires
                int nextc = c + acquires;
                //和小于0表明锁重入次数已经超过上限
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

NonfairSync类负责非公平锁 ,成员函数也很简单 仅有lock与tryAcquire两个,tryAcquire直接调用父类Sync的nonfairTryAcquire方法(这里吐槽下, nonfairTryAcquire感觉本来就应该放到NonfairSync类里面, 偏偏放Sync里面了,还绕了一个弯调用, 作者不知道咋想的 。。。)

 static final 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跟NonfairSync一样也只有两个成员函数lock 与tryAcquire

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        //不再快速尝试获取锁 而是直接排队获取
        final void lock() {
            acquire(1);
        }
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
             //发现锁没人持有 并且等待队列是空的或者头结点线程就是当前线程 则cas尝试获取锁,
                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;
        }
    }

ReentrantLock 构造函数

  //默认是非公平锁
	public ReentrantLock() {
       sync = new NonfairSync();
   }
   
   //指定是哪种锁
   public ReentrantLock(boolean fair) {
       sync = fair ? new FairSync() : new NonfairSync();
   }

lock

直接调用内部类的lock

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

unlock

直接调用内部类的unlock

public void unlock() {
       sync.release(1);
   }
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值