ReentrantReadWriteLock源码---JDK1.8
/**
* 读写锁:
* 1.读锁使用共享模式,写锁使用独占模式
* 2.写锁独占,所以会阻塞读锁和写锁,读锁共享,所以只会阻塞写锁
* 3.写锁可以降级为读锁,读锁不能升级写锁
*/
看看构造方法:
//默认为非公平模式 public ReentrantReadWriteLock() { this(false); } public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); }
看看内部类Sync:
/** * Sync继承自AQS,在ReentrantReadWriteLock这里,state被分为2部分 * 高16位,用来表示读锁的持有次数,低16位表示写锁的持有次数。 * int: * 1---> 0000 0000 0000 0000 0000 0000 0000 0001 * SHARED_UNIT---> 0000 0000 0000 0001 0000 0000 0000 0000 * MAX_COUNT---> 0000 0000 0000 0000 1111 1111 1111 1111 * EXCLUSIVE_MASK---> 0000 0000 0000 0000 1111 1111 1111 1111 */ static final int SHARED_SHIFT = 16; //左移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; //每个线程持有读锁次数的计数器,在ThreadLocal中管理, static final class HoldCounter { int count = 0; // Use id, not reference, to avoid garbage retention final long tid = getThreadId(Thread.currentThread()); }
/** * 独占模式请求的过程: * 1.如果锁的持有者不是当前线程,且读锁或者写锁持有次数不为0,请求失败。 * 2.如果锁持有次数超过上限,请求失败。 * 3.没超过次数,如果当前是一个重入请求,或者队列策略允许, * 那么当前线程可以获取锁,更新状态并设置锁所有者。 */ protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); int c = getState(); //获取写锁持有次数 int w = exclusiveCount(c); if (c != 0) { // (Note: if c != 0 and w == 0 then shared count != 0) //c !=0,说明锁被持有,如果w=0,说明当前锁是读锁,再检查一下当前线程是不是 //持有者 if (w == 0 || current != getExclusiveOwnerThread()) //如果不是,获取失败 return false; //检查写锁持有次数是否超过最大值MAX_COUNT if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); // Reentrant acquire //更新设置重入次数 setState(c + acquires); return true; } //到这里说明c=0,说明锁没有被持有, //如果写锁需要阻塞或者CAS尝试设置状态失败 if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) //请求失败 return false; //到这里说明写锁不需要阻塞或者CAS成功,那么需要设置当前线程为持有者 setExclusiveOwnerThread(current); return true; }
//独占模式下尝试释放锁 protected final boolean tryRelease(int releases) { //检查是否是独占模式 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //状态值减去释放值,得到新的状态值 int nextc = getState() - releases; //判断重入次数是否为0 boolean free = exclusiveCount(nextc) == 0; if (free) //为0,释放锁, setExclusiveOwnerThread(null); //更新状态值 setState(nextc); return free; }
/** * 共享模式下尝试请求: * 1.如果其他线程持有写锁,请求失败。 * 2.重入次数超过最大值,抛异常 * 3.再判断当前队列策略是否需要阻塞读请求, * 如果不需要,尝试CAS修改状态,如果修改成功, * 更新重入次数,请求成功。 */ protected final int tryAcquireShared(int unused) { Thread current = Thread.currentThread(); int c = getState(); //写锁重入次数 if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) //如果c!=0,说明锁被持有,检查当前线程是不是持有者,不是,请求失败 return -1; //获取写锁重入次数 int r = sharedCount(c); //判断读锁是否需要阻塞,检查锁重入次数,尝试CAS更新状态 if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { if (r == 0) { //如果r=0,说明锁没有被持有,当前线程设置为第一个, firstReader = current; firstReaderHoldCount = 1; } else if (firstReader == current) { //如果还是自己抢到锁了,更新重入值 firstReaderHoldCount++; } else { //获取缓存的HoldCounter HoldCounter rh = cachedHoldCounter; //判断rh,是否有值,如果没有值,且不是当前线程的HoldCounter if (rh == null || rh.tid != getThreadId(current)) //从缓存中获取当前线程的HoldCounter cachedHoldCounter = rh = readHolds.get(); // else if (rh.count == 0) readHolds.set(rh); //计数增加 rh.count++; } return 1; } return fullTryAcquireShared(current); }
static final class NonfairSync extends Sync { //非公平模式下,写总是可以插队 final boolean writerShouldBlock() { return false; // writers can always barge } final boolean readerShouldBlock() { //如果同步等待队列头部有写请求,那么当前读请求阻塞 return apparentlyFirstQueuedIsExclusive(); } }
//公平模式,读写锁是否需要阻塞,就是检查同步等待队列是否有更早的线程 static final class FairSync extends Sync { // final boolean writerShouldBlock() { return hasQueuedPredecessors(); } final boolean readerShouldBlock() { return hasQueuedPredecessors(); } }
再看看内部类ReadLock:
//读锁实现 public static class ReadLock implements Lock, java.io.Serializable { private final Sync sync; protected ReadLock(ReentrantReadWriteLock lock) { sync = lock.sync; } //请求读锁 //如果有其他线程持有写锁,那么阻塞当前线程,直到请求成功 //如果没有其他线程持有写锁,那么请求成功 public void lock() { sync.acquireShared(1); } //响应中断,读锁请求 public void lockInterruptibly() throws InterruptedException { sync.acquireSharedInterruptibly(1); } //如果没有其他线程持有写锁,那么请求读锁成功 //读锁是共享锁,所以总会立即成功 //这里会打破公平策略,如果想遵循策略调用tryLock(0,TimeUni public boolean tryLock() { return sync.tryReadLock(); } //支持超时,中断的读锁请求。 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } //读锁释放 public void unlock() { sync.releaseShared(1); } //读锁不支持条件, public Condition newCondition() { throw new UnsupportedOperationExc }
内部类WriteLock:
//写锁实现 public static class WriteLock implements Lock, java.io.Serializable { private final Sync sync; protected WriteLock(ReentrantReadWriteLock lock) { sync = lock.sync; } //请求写锁。 //如果锁没有被线程持有,那么请求写锁成功。 //如果当前线程已经持有了写锁,叠加重入次数 //如果有其他线程持有当前锁,当前线程阻塞,直到请求锁成功 public void lock() { sync.acquire(1); } //支持中断锁请求,响应中断 public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } //如果锁没有被线程持有,那么请求写锁成功。 //这里会打破公平策略,如果想遵循策略调用tryLock(0,TimeUnit.SECONDS) //如果当前线程已经持有了写锁,叠加重入次数 //如果有其他线程持有当前锁,返回失败 public boolean tryLock() { return sync.tryWriteLock(); } //支持超时中断的读锁请求 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); } //检查写锁是否被当前线程持有,写锁是独占锁 public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } }
知识的学习,要真诚与谦虚才不会有眼无珠,人生苦短,不能浪费时间做无用功。
人生学习最悲哀的不过是,因为无知傲慢错过真正的好东西,又因为无知贪婪在假东西上耗费生命。