【并发编程】ReentrantLock

ReentrantLock是什么

    ReentrantLock继承自AbstractQueuedSynchronizer,即AQS, AQS可以理解为一个线程排队获取CPU的队列。队列中放的是一个个的Node。

  *      +------+  prev +-----+       +-----+
  * head |      | <---- |     | <---- |     |  tail
  *      +------+       +-----+       +-----+
 	volatile Node prev;
 	volatile Node next;
 	volatile Thread thread;

加锁过程

通过以下代码模拟多线程竞争锁的场景

public class Example1 {
	public static void main(String[] args) {
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,5,2000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
		ReentrantLock reentrantLock = new ReentrantLock(true);
		for (int i = 0; i < 3; i++) {
			threadPoolExecutor.submit(() -> {
				reentrantLock.lock();
				logic();
				reentrantLock.unlock();
			});
		}
		threadPoolExecutor.shutdown();
	}

	public static void logic() {
		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

head == tail == null

在这里插入图片描述

  • 第一个线程调用tryAcquire(arg)过来获取锁,此时state为0,说明锁是空闲状态,可以继续执行获取流程。
  • 接下来尝试获取锁,首先通过hasQueuedPredecessors()判断队列有没有线程在排队,第一个线程过来时队列时空的,head==tail ==null,即没有线程排队。
  • 直接尝试CAS获取锁
    在这里插入图片描述
  • 如果获取成功,记录锁被当前线程持有,setExclusiveOwnerThread(current)。

head == tail != null

  • 第二个线程调用tryAcquire(arg)过来获取锁,此时state为1,不会继续执行获取锁的流程,但是会判断是否重入锁。
  • 如果getExclusiveOwnerThread()是当前线程,则该线程可以得到锁。
  • 否则进入队列
    在这里插入图片描述
    入队列之前会将当前线程封装成一个Node,Node的前一个节点prev为第一个线程对应的Node,Node的下一个节点next为null,即该Node为tail节点。
    在这里插入图片描述
  • 入队列之后继续尝试获取锁
    在这里插入图片描述
	// 当该节点的上一个节点是head节点时才尝试再次获取锁
	if (p == head && tryAcquire(arg)) {
		setHead(node);
	    p.next = null; // help GC
	    failed = false;
	    return interrupted;
	}
  • 第二个线程走到这里是满足条件的,可以获取到锁。
    在这里插入图片描述

head != tail

  • 第三个线程调用tryAcquire(arg)过来获取锁,此时state为1,不会继续执行获取锁的流程。
  • 进入队列继续尝试获取锁。
  • 第三个线程的前一个Node不是head,所以不能紧接着尝试获取锁。
    在这里插入图片描述
  • 判断是否需要park,第三个线程此时不需要park。(暂未模拟到需要park的场景)
  • 尝试获取锁。
  • 获取锁成功。

解锁过程

  • tryRelease(1)尝试解锁
    在这里插入图片描述
    在这里插入图片描述
    tryRelease依据state是否为0来判断是否解锁成功,不为0时说明存在锁重入的情况。
  • 解锁成功判断队列中是否还有Node排队
    在这里插入图片描述
    如果还有Node在队列中,则调用LockSupport.unpark唤醒排队线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值