二十三、ReentrantReadWriteLock之初识读锁加锁流程

56 阅读2分钟

ReentrantReadWriteLock之初识读锁加锁流程

读锁加锁的初步流程:

  1. 获取state值
  2. 如果有线程持有写锁,并且持有写锁的不是当前线程,进入同步队列中排队
  3. 如果没有线程持有锁,或者持有写锁的是当前线程,竞争读锁
  4. 如果竞争的是非公平锁,如果同步队列中没有节点排队,竞争读锁
  5. 如果有节点排队,但head的next是读线程,当前线程依然可以竞争读锁
  6. 如果head的next是写线程,则需要继续判断当前线程是否是锁重入
  7. 如果是,执行锁重入过程,如果不是,进入同步队列中排队
  8. 如果竞争的是公平锁,如果同步队列中没有节点在排队,竞争读锁,
  9. 如果有,则需要继续判断当前线程是否是锁重入
  10. 如果是,执行锁重入过程,如果不是,进入同步队列中排队
public void lock() {
	sync.acquireShared(1);
}

public final void acquireShared(int arg) {
	// 判断是否获取读锁成功
	// 如果tryAcquireShared(arg) < 0 说明获取失败,需要放入同步队列中
	// 否则获取成功,直接返回
	if (tryAcquireShared(arg) < 0)
		doAcquireShared(arg);
}

protected final int tryAcquireShared(int unused) {

	Thread current = Thread.currentThread();
	// 获取state值
	int c = getState();
	// 判断是否有线程持有写锁,判断是否是当前线程持有写锁
	if (exclusiveCount(c) != 0 &&
		getExclusiveOwnerThread() != current)
		// 不是当前线程持有写锁
		return -1;
	// 没有线程持有写锁,或者当前线程持有写锁
	// 获取state高16位值
	int r = sharedCount(c);
	// 竞争公平锁:查看同步队列中是否有线程排队,如果有不进入if中,直接去执行fullTryAcquireShared方法
	// 竞争非公平锁:查看同步队列中是否有线程排队,没有就抢锁资源;
	// 有排队的,但是head的next是读线程,那么就继续抢锁资源
	// 如果是写线程,不进入if中,直接去执行fullTryAcquireShared方法
	if (!readerShouldBlock() &&
		r < MAX_COUNT &&
		compareAndSetState(c, c + SHARED_UNIT)) {
		// 此处省略代码...
		return 1;
	}
	// 抢锁失败,继续抢锁
	return fullTryAcquireShared(current);
}

readerShouldBlock方法在公平锁和非公平锁下有不同的实现
非公平锁:

final boolean readerShouldBlock() {
	// apparentlyFirstQueuedIsExclusive方法
	// 当同步队列中有写线程节点时,返回true
	// 当同步队列中没有写线程节点时,返回false
	return apparentlyFirstQueuedIsExclusive();
}

final boolean apparentlyFirstQueuedIsExclusive() {
	Node h, s;
	return (h = head) != null &&
		(s = h.next)  != null &&
		!s.isShared()         &&
		s.thread != null;
}

公平锁:

final boolean readerShouldBlock() {
	// hasQueuedPredecessors方法
	// 如果同步队列中有节点,返回true
	// 如果同步队列中没有节点,返回false
	return hasQueuedPredecessors();
}

public final boolean hasQueuedPredecessors() {
	Node t = tail; // Read fields in reverse initialization order
	Node h = head;
	Node s;
	return h != t &&
		((s = h.next) == null || s.thread != Thread.currentThread());
}