ReentrantLock源码

本文详细分析了ReentrantLock的内部实现机制,包括其继承结构、核心方法lock的执行流程,以及AQS队列的运作原理。通过源码解读,阐述了公平锁的工作过程,从线程获取锁到释放锁的全过程,以及线程自旋、CAS操作、park和unpark等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ReentrantLock的源码分析:

ReentrantLock:

public class ReentrantLock implements Lock, java.io.Serializable

abstract static class Sync extends AbstractQueuedSynchronizer

static final class FairSync extends Sync {
	
	final void lock() {
		acquire(1);
	}
	
	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;
	}

}

static final class NonfairSync extends Sync

AQS:

public abstract class AbstractQueuedSynchronizer
	extends AbstractOwnableSynchronizer
    implements java.io.Serializable

private transient Thread exclusiveOwnerThread;

private transient volatile Node head;

private transient volatile Node tail;

private volatile int state;	

static final class Node {
     
        static final Node SHARED = new Node();

        static final Node EXCLUSIVE = null;


        static final int CANCELLED =  1;
  
        static final int SIGNAL    = -1;

        static final int CONDITION = -2;
  
        static final int PROPAGATE = -3;
		
		volatile int waitStatus;
		
		volatile Node prev;
		
		volatile Node next;
		
		volatile Thread thread;
		
		Node nextWaiter;		
		
		// 排队
		private Node enq(final Node node) {
        for (;;) {
            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 final void acquire(int arg) {
	if (!tryAcquire(arg) &&
		acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
		selfInterrupt();
}

// 判断队列有没有初始化
public final boolean hasQueuedPredecessors() {
	Node t = tail; 
	Node h = head;
	Node s;
	return h != t &&  // 如果 h == t 说明队列没有元素或有一个元素,h != t 说明队列至少有两个元素
 		((s = h.next) == null || s.thread != Thread.currentThread());
}

// 入队
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;
}

// 自旋
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)
			cancelAcquire(node);
	}
}

// 是否要进入自旋:只有队列的第一个队列需要进行自旋操作
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
	int ws = pred.waitStatus;
	
	// 如果上一个Node的waitStatus == -1.
	if (ws == Node.SIGNAL)
		return true;
	if (ws > 0) {
		
		do {
			node.prev = pred = pred.prev;
		} while (pred.waitStatus > 0);
		pred.next = node;
	} else {
		// 如果上一个Node的waitStatus == 0,就设置为 -1(代表获取锁)
		compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
	}
	return false;
}

锁:解决多线程并发同步问题

1)自旋
2)CAS
3)park和unpark (USAFE)
4)在线程交替执行(没有竞争锁)和队列无关,在jdk级别解决同步问题。

公平锁示例:lock

1)第一个线程t1获取锁时,先查看 status == 0 && 队列有没有初始化-没有,对status进行cas操作(status = 1)获取锁,使当前线程为执行线程。
2)第二个线程t2获取锁时,先查看 status == 1 && 当前线程不是执行线程,执行入队操作:判断队列有没有初始化-没有,先创建一个 thread = null 的节点,再创建 thread = t2 的 Node 放在 null Node 后面,先尝试获取锁,如果获取不到就park,进入自旋。
3)第三个线程t3获取锁时,先查看 status == 1 && 当前线程不是执行线程,执行入队操作:判断队列有没有初始化-有,创建thread = t3 的 Node 放在 t2 后面。

t1 释放锁,status == 0 通知队列

4)第四个线程t4获取锁时,先查看 status == 0 && 队列有没有初始化-有,入队。

扩展:acquireQueued 的 interrupted 是给下面方法使用的

interrupt(),在一个线程中调用另一个线程的interrupt()方法,即会向那个线程发出信号——线程中断状态已1653被设置。至于那个线程何去何从,由具体的代码实现决定。
isInterrupted(),用来判断当前线程的中断状态(true or false)。
interrupted()是个Thread的static方法,用来恢复中断状态

try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
//处理 InterruptedException
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值