大家推荐个靠谱的公众号程序员探索之路,公众号内点击网赚获取彩蛋,大家一起加油,这个公众号已经接入图灵
======================================
1.ReentrantReadWriteLock属性和读/写锁 概要
======================================
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** Performs all synchronization mechanics */
final Sync sync;
/**
* 读锁
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* Acquires the read lock.
*
* <p>Acquires the read lock if the write lock is not held by
* another thread and returns immediately.
*
* <p>If the write lock is held by another thread then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until the read lock has been acquired.
*/
public void lock() {
sync.acquireShared(1);
}
.....
/**
* 写锁
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* Acquires the write lock.
*
* <p>Acquires the write lock if neither the read nor write lock
* are held by another thread
* and returns immediately, setting the write lock hold count to
* one.
*
* <p>If the current thread already holds the write lock then the
* hold count is incremented by one and the method returns
* immediately.
*
* <p>If the lock is held by another thread then the current
* thread becomes disabled for thread scheduling purposes and
* lies dormant until the write lock has been acquired, at which
* time the write lock hold count is set to one.
*/
public void lock() {
sync.acquire(1);
}
......
没什么注释,因为没什么好说的这块
================================
2.ReentrantReadWriteLock里的sync
================================
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*
读写锁将锁状态state 高16位用于共享模式 低16位用于独占模式
*/
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/**
取高16位的值 代表读锁的获取次数(包括重入)
*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/**
取低16位的值 代表写锁的重入次数 ???为什么不是获取次数 写锁是独占模式拉
*/
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/**
* 这个类的实例 代表的是线程持有的读锁的数量
*/
static final class HoldCounter {
int count = 0;
// 或者线程的id
final long tid = getThreadId(Thread.currentThread());
}
/**
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
记录当前线程的读锁重入次数
*/
private transient ThreadLocalHoldCounter readHolds;
/**
用于缓存,记录最后一个获取读锁的线程的重入次数
*/
private transient HoldCounter cachedHoldCounter;
/**
第一个获取读锁的线程(并且未释放读锁),以及它持有的读锁数量
*/
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
==================
3.读锁的lock/unlock
==================
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
//如果 < 0代表没有获取锁
if (tryAcquireShared(arg) < 0)
//没有获取锁进入等待队列
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail.
* 2. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 3. If step 2 fails either because thread
* apparently not eligible or CAS fails or count
* saturated, chain to version with full retry loop.
*/
Thread current = Thread.currentThread();
int c = getState();
//如果有 写锁 并且 当前占有锁的线程不是 本线程 返回-1 那么返回到外层就是进入等待队列 注意这里的条件 有写锁而且有锁的不是本线程返回-1
//也就是说 如果有写锁 但是获取写锁的线程是本线程 是可以获取读锁的 这中操作叫做锁降级 相反不能锁升级
//我猜的锁降级的作用是提升性能 因为本线程对内容的修改(也就是写操作)在自己的线程栈中是可见的 所以也能获取读锁
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//获取读锁(也就是共享锁)的数量
int r = sharedCount(c);
//允许获取锁 并且 锁的总数量 < 最大锁数量 并且 将 state 属性的高 16 位加 1,低 16 位不变 如果成功就代表获取到了读锁
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//下面都是未获取锁的
//如果r == 0表示 在此获取之前没有线程获取过读锁 设置第一个获取读锁的线程
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
//如果是第一个获取读锁的重入
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
//这个分支是 更新缓存获取最后一个读锁的线程
HoldCounter rh = cachedHoldCounter;
//更新最后
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
/**
* 这个方法的目的是 上面先判断没有线程占有写锁 但是读线程获取锁失败 这里表示不服 需要重新试一次
*/
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
HoldCounter rh = null;
//注意这是一个循环
for (;;) {
int c = getState();
//和之前的判断一样如果有 写锁 并且 当前占有锁的线程不是 本线程 返回-1 那么返回到外层就是进入等待队列
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// else we hold the exclusive lock; blocking here
// would cause deadlock.
} else if (readerShouldBlock()) {
//走到这块里面表示 可以阻塞读锁 下面的做到判断是 重入的处理
// Make sure we're not acquiring read lock reentrantly
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
//这里发现 缓存的本线程的读锁获取次数为0 那么就是初始化的值 所以不好意思 你不是重入乖乖等待
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
//重入锁的最大数量判断
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//尝试获取锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
/**
判断读锁是否应该阻塞 true 是 false 不是
公平模式下 队列中有元素就排对 重入除外
非公平模式下 如果是重入那么不等待 如果不是重入且head.next是写锁那么等待 如果不是重入而且head.next不是写锁那么大家公平竞争比cas速度
*/
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
/**
公平模式
*/
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
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());
}
/**
* Nonfair version of Sync 非公平模式
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* Acquires in shared uninterruptible mode.
* @param arg the acquire argument
这个和之前分析的aqs 一样 都是 在等待队列中等待
*/
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
------------释放锁
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
/**
*/
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
//处理如果是第一个获取锁的线程
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
//如果当前线程刚好是 最后一个,如果不是获取该线程获取锁的次数
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
//锁获取次数修改
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
//循环设置读锁状态
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
/**
这个就是真正唤醒的操作 和之前分析的aqs一样
*/
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
==================
4.写锁的lock/unlock
==================
public void lock() {
sync.acquire(1);
}
//看着是不是很熟悉 其实就是tryAcquire不一样 另外的点是一样的
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
//获取写锁状态
int w = exclusiveCount(c);
//c != 0 表示有可能有线程占用了锁 但是得具体看看
if (c != 0) {
// 看下这里返回 false 的情况:
// c != 0 && w == 0: 写锁可用,但是有线程持有读锁(也可能是自己持有)
// c != 0 && w !=0 && current != getExclusiveOwnerThread(): 其他线程持有写锁
// 也就是说,只要有读锁或写锁被占用,这次就不能获取到写锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
//一路走来成功了 就是获取了
return true;
}
//如果不能获取写锁 或者cas state失败 返回false
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
//设置获取锁的线程
setExclusiveOwnerThread(current);
return true;
}
static final class NonfairSync extends Sync {
// 如果是非公平模式,那么 lock 的时候就可以直接用 CAS 去抢锁,抢不到再排队
final boolean writerShouldBlock() {
return false; // writers can always barge
}
}
static final class FairSync extends Sync {
final boolean writerShouldBlock() {
// 如果是公平模式,那么如果阻塞队列有线程等待的话,就乖乖去排队
return hasQueuedPredecessors();
}
}