ReentrantReadWriteLock
一、概述
二、源码
1、实现接口
public interface ReadWriteLock { Lock readLock(); Lock writeLock(); } |
2、属性
//读锁 private final ReentrantReadWriteLock.ReadLock readerLock; //写锁 private final ReentrantReadWriteLock.WriteLock writerLock; //内部同步器 final Sync sync; |
3、构造方法
public ReentrantReadWriteLock() { this ( false ); } public ReentrantReadWriteLock( boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock( this ); writerLock = new WriteLock( this ); } public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } |
4、内置同步器和锁实现
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 6317671515068378041L; //高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 ; //共享数量 static int sharedCount( int c) { return c >>> SHARED_SHIFT; } //独占数量 static int exclusiveCount( int c) { return c & EXCLUSIVE_MASK; } //重入计数器,内部类,重入次数和线程 static final class HoldCounter { int count = 0 ; final long tid = getThreadId(Thread.currentThread()); } //重入计数器ThreadLocal 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()); } abstract boolean readerShouldBlock(); abstract boolean writerShouldBlock(); protected final boolean tryRelease( int releases) { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); int nextc = getState() - releases; boolean free = exclusiveCount(nextc) == 0 ; if (free) setExclusiveOwnerThread( null ); setState(nextc); return free; } protected final boolean tryAcquire( int acquires) { Thread current = Thread.currentThread(); int c = getState(); int w = exclusiveCount(c); if (c != 0 ) { //有读锁存在,独占线程非当前线程,就返回false if (w == 0 || current != getExclusiveOwnerThread()) return false ; if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error( "Maximum lock count exceeded" ); setState(c + acquires); return true ; } //如果读写锁都没被获取,如果写锁竞争时需要阻塞或状态更新不成功 if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false ; //持有线程 setExclusiveOwnerThread(current); return true ; } 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 ; } } private IllegalMonitorStateException unmatchedUnlockException() { return new IllegalMonitorStateException( "attempt to unlock read lock, not locked by current thread" ); } protected final int tryAcquireShared( int unused) { Thread current = Thread.currentThread(); int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return - 1 ; int r = sharedCount(c); if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { 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) { HoldCounter rh = null ; for (;;) { int c = getState(); 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 { 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 ; } } } final boolean tryWriteLock() { Thread current = Thread.currentThread(); int c = getState(); if (c != 0 ) { int w = exclusiveCount(c); if (w == 0 || current != getExclusiveOwnerThread()) return false ; if (w == MAX_COUNT) throw new Error( "Maximum lock count exceeded" ); } if (!compareAndSetState(c, c + 1 )) return false ; setExclusiveOwnerThread(current); return true ; } final boolean tryReadLock() { Thread current = Thread.currentThread(); for (;;) { int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return false ; int r = sharedCount(c); if (r == MAX_COUNT) throw new Error( "Maximum lock count exceeded" ); if (compareAndSetState(c, c + SHARED_UNIT)) { 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 true ; } } } protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } final Thread getOwner() { return ((exclusiveCount(getState()) == 0 ) ? null : getExclusiveOwnerThread()); } final int getReadLockCount() { return sharedCount(getState()); } final boolean isWriteLocked() { return exclusiveCount(getState()) != 0 ; } final int getWriteHoldCount() { return isHeldExclusively() ? exclusiveCount(getState()) : 0 ; } final int getReadHoldCount() { if (getReadLockCount() == 0 ) return 0 ; Thread current = Thread.currentThread(); if (firstReader == current) return firstReaderHoldCount; HoldCounter rh = cachedHoldCounter; if (rh != null && rh.tid == getThreadId(current)) return rh.count; int count = readHolds.get().count; if (count == 0 ) readHolds.remove(); return count; } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); readHolds = new ThreadLocalHoldCounter(); setState( 0 ); // reset to unlocked state } final int getCount() { return getState(); } } static final class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false ; // writers can always barge } final boolean readerShouldBlock() { return apparentlyFirstQueuedIsExclusive(); } } static final class FairSync extends Sync { private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() { return hasQueuedPredecessors(); } final boolean readerShouldBlock() { return hasQueuedPredecessors(); } } public static class ReadLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; 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 ); } 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 UnsupportedOperationException(); } public String toString() { int r = sync.getReadLockCount(); return super .toString() + "[Read locks = " + r + "]" ; } } public static class WriteLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; 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 ); } 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(); } public int getHoldCount() { return sync.getWriteHoldCount(); } } |
5、一般方法
public final boolean isFair() { return sync instanceof FairSync; } protected Thread getOwner() { return sync.getOwner(); } public int getReadLockCount() { return sync.getReadLockCount(); } public boolean isWriteLocked() { return sync.isWriteLocked(); } public boolean isWriteLockedByCurrentThread() { return sync.isHeldExclusively(); } public int getWriteHoldCount() { return sync.getWriteHoldCount(); } public int getReadHoldCount() { return sync.getReadHoldCount(); } protected Collection<Thread> getQueuedWriterThreads() { return sync.getExclusiveQueuedThreads(); } protected Collection<Thread> getQueuedReaderThreads() { return sync.getSharedQueuedThreads(); } public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } public final int getQueueLength() { return sync.getQueueLength(); } protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } public boolean hasWaiters(Condition condition) { if (condition == null ) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException( "not owner" ); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } public int getWaitQueueLength(Condition condition) { if (condition == null ) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException( "not owner" ); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null ) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException( "not owner" ); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } public String toString() { int c = sync.getCount(); int w = Sync.exclusiveCount(c); int r = Sync.sharedCount(c); return super .toString() + "[Write locks = " + w + ", Read locks = " + r + "]" ; } static final long getThreadId(Thread thread) { return UNSAFE.getLongVolatile(thread, TID_OFFSET); } private static final sun.misc.Unsafe UNSAFE; private static final long TID_OFFSET; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> tk = Thread. class ; TID_OFFSET = UNSAFE.objectFieldOffset (tk.getDeclaredField( "tid" )); } catch (Exception e) { throw new Error(e); } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步