ReentrantLock源码分析

13 篇文章 0 订阅
本文详细解读了ReentrantLock的源码,包括其构造函数、lock()方法的实现,以及非公平锁和公平锁的tryAcquire方法。通过分析,揭示了ReentrantLock如何在多线程环境下确保资源的正确锁定和释放。
摘要由CSDN通过智能技术生成

首先,想先梳理一下自己看源码的目的,最近有篇文章特别火《程序员12小时惊魂记:凌晨迁移数据出大事故!》,里面强调了解决问题的能力很重要,这给我一种只看源码和设计模式关键时刻不给力的感觉,周末去看了鲁能和恒大的比赛,那种在瞬间做出决策的压力只会比事故现场更紧张,而且不能有一点犹豫。我想竞技体育的魅力,就在于此吧,要把所有的技能都训练到潜意识层面,才会在瞬间爆发出来。所以,要不断的研究不断的实践,弄懂原理,融汇贯通。

看源码步骤:
1、选中类名右击,选中Giaggrams->Show Diagram查看类关系图。
2、在类关系图中右击,选中Show Categories->Methods等查看类属性和方法等。可以看到ReentrantLock实现了Lock,Serializable两个接口,有Sync、NonfairSync和FairSync三个内部类,NonfairSync和FairSync继承Sync类,Sync继承和ReentrantLock同一个包下的AbstractQueuedSynchronizer抽象类。
3、在自己的测试工程中写一个测试类,创建ReentrantLock对象,调用其中的方法。

public class ReentrantLockTest {
	public static void main(String[] args){
		ReentrantLock reentrantLock = new ReentrantLock();
		reentrantLock.lock();
		reentrantLock.unlock();
	}
}

(1)从构造函数开始看,无参构造方法中只是实现了sync = new NonfairSync(),即默认使用非公平锁。
(2)常用的方法lock(),实现很简单,只是调用了sync.lock(),抽象方法,由子类实现。查看默认的非公平锁的实现。

final void lock(){
	if (compareAndSetState(0,1)){
		setExclusiveOwnerThread(Thread.currentThread());
	} else{
		acquire(1);
	}
}

public final void acquire(int arg){
	if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE),arg)){
		selfInterrupt();
	}
}
  1. setExclusiveOwnerThread把当前线程设置成持有锁的线程。
  2. 如果CAS失败,说明锁已经被别人获取,那么通过acquire()尝试去获取锁。
  3. 其中的抽象类的非抽象方法,AbstractQueuedSynchronizer.java中tryAcquire方法,在抽象类中只是简单了抛出了异常,这种主要是由子类去实现,要去看不同的子类都是怎么实现的该方法。这个方法中,由FairSync公平锁和NonFairSync非公平锁的来实现此方法。
  4. tryAcquire方法以独占的方式获取锁,说白了就是,再获取一遍锁的状态,如果还是没人获取,就用CAS再获取一遍,如果有人获取了,恰巧是自己线程,那就把状态+1,其他情况都是获取锁失败,这时候线程就会进入等待队列。下面看下非公平锁实现的tryAcquire的实现。
  5. 在NonFairSync非公平锁中调用nonfairTryAcquire(acquires);
final boolean nonfairTryAcquire(int acquires){
	final Thread current = Thread.currentThread();
	int c = getStatus();
	if (c == 0){
		if (compareAndSetState(0,1)){
			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;
}
  • getStatus()获取的状态,就是上面CAS设置的状态,如果状态(c ==
    0)说明当前没有任何线程获取到锁,那就再获取一遍锁,设置线程,返回true;
  • current == getExclusiveOwnerThread()说明当前线程重入
  • setState(),把重入次数+1更新到status,返回true说明获取到这个锁。
  1. 继续看acquire()方法中的判断条件,addWaiter(Node.EXCLUSIVE)中 EXCLUSIVE定义 = null; 注释中表明,此标记表示节点在独占模式下等待。
private Node addWaiter(Node mode){
	Node node = new Node(Thread.currentThread(),mode);
	Node pred = tail;
	if (pred != null){
		node.prev = pred;
		if (compareAndSetTail(pred,node)){
			pred.next = node;
			return node;
		}
	}
	enq(node);
	return node;
}

private Node enq(final Node node){
	for (;;){ // me:原来必须初始化是这样写
		Node t = tail;
		if (t == null){ //Must initialize
			if (compareAndSetHead(new Node())){
				tail = head;
			}
		} else {
			node.prev = t;
			if (compareAndSetTail(t,node)){
				t.next = node;
				return t;
			}
		}
	}
}
public abstract class AbstractQueuedSynchronizer 
	extends AbstractOwnableSynchronizer 
	implements java.io.Serializable {
	
	static final class Node{
		...
		volatile Node prev;
		volatile Node next;
		volatile Thread thread;
		Node nextWaiter;
		Node(Thread thread, Node mode){
			this.nextWaiter = mode;
			this.thread = thread;
		}
		...
	}
}
  • pred != null,说明当前链表不为空,则把node追加到链表的尾部,并返回node。
  • addWaiter()方法保证把Node放到一个链表里去,并返回尾节点。
  1. 继续看acquire()方法中的判断条件,acquireQueued(addWaiter(Node.EXCLUSIVE),arg))
final boolean acquireQueued(final Node node, int arg){
	boolean failed = true;
	try {
		boolean interrupted = false;
		for (;;){
			final Node p = node.predecessor();
			if (p == head && tryAcquire(arg)){
				setHead(node);
				p.next = null; //help GC
				failed = false;
				return interrupted;
			}
			if (shouldParkAfterFailedAcquire(p,node) && 
				parkAndCheckInterrupt()){
				interrupted = true;
			}
		}
	} finally {
		if (failed)
			cancleAcquire(node);
	}
}
  • p == head是链表的特性,head节点不存数据,所以如果当前节点的前驱节点为head时,则移除掉原head,把当前node节点设置为head。
  • shouldParkAfterFailedAcquire()里面有信号量,第一次执行结果为false,且设置信号量,继续执行for的死循环,使用信号量,将线程挂起,然后等待一直线程被唤起。
  • finally表示如果执行过程中有异常情况,则取消当前线程获取锁的动作。
  • for循环,从传入的尾节点开始,不断的获取前驱节点,只有在获取到head节点时,才能走到唯一的出口
  1. 继续看acquire(),如果获取锁过程中有中断标记,则中断当前线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值