📄 reentrantreadwritelock.java
字号:
* and set owner. */ 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) if (w == 0 || current != getExclusiveOwnerThread()) return false; if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); } if ((w == 0 && writerShouldBlock(current)) || !compareAndSetState(c, c + acquires)) return false; setExclusiveOwnerThread(current); return true; } protected final boolean tryReleaseShared(int unused) { HoldCounter rh = cachedHoldCounter; Thread current = Thread.currentThread(); if (rh == null || rh.tid != current.getId()) rh = readHolds.get(); if (rh.tryDecrement() <= 0) throw new IllegalMonitorStateException(); for (;;) { int c = getState(); int nextc = c - SHARED_UNIT; if (compareAndSetState(c, nextc)) return nextc == 0; } } protected final int tryAcquireShared(int unused) { /* * Walkthrough: * 1. If write lock held by another thread, fail * 2. If count saturated, throw error * 3. 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. * 4. If step 3 fails either because thread * apparently not eligible or CAS fails, * chain to version with full retry loop. */ Thread current = Thread.currentThread(); int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (!readerShouldBlock(current) && compareAndSetState(c, c + SHARED_UNIT)) { HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != current.getId()) cachedHoldCounter = rh = readHolds.get(); rh.count++; return 1; } return fullTryAcquireShared(current); } /** * Full version of acquire for reads, that handles CAS misses * and reentrant reads not dealt with in tryAcquireShared. */ 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 = cachedHoldCounter; if (rh == null || rh.tid != current.getId()) rh = readHolds.get(); for (;;) { int c = getState(); int w = exclusiveCount(c); if ((w != 0 && getExclusiveOwnerThread() != current) || ((rh.count | w) == 0 && readerShouldBlock(current))) return -1; if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (compareAndSetState(c, c + SHARED_UNIT)) { cachedHoldCounter = rh; // cache for release rh.count++; return 1; } } } /** * Performs tryLock for write, enabling barging in both modes. * This is identical in effect to tryAcquire except for lack * of calls to writerShouldBlock */ 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; } /** * Performs tryLock for read, enabling barging in both modes. * This is identical in effect to tryAcquireShared except for * lack of calls to readerShouldBlock */ final boolean tryReadLock() { Thread current = Thread.currentThread(); for (;;) { int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return false; if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (compareAndSetState(c, c + SHARED_UNIT)) { HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != current.getId()) cachedHoldCounter = rh = readHolds.get(); rh.count++; return true; } } } protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } // Methods relayed to outer class final ConditionObject newCondition() { return new ConditionObject(); } final Thread getOwner() { // Must read state before owner to ensure memory consistency 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() { return getReadLockCount() == 0? 0 : readHolds.get().count; } /** * Reconstitute this lock instance from a stream * @param s the stream */ 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(); } } /** * Nonfair version of Sync */ final static class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock(Thread current) { return false; // writers can always barge } final boolean readerShouldBlock(Thread current) { /* 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 probablistic 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(); } } /** * Fair version of Sync */ final static class FairSync extends Sync { private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock(Thread current) { // only proceed if queue is empty or current thread at head return !isFirst(current); } final boolean readerShouldBlock(Thread current) { // only proceed if queue is empty or current thread at head return !isFirst(current); } } /** * The lock returned by method {@link ReentrantReadWriteLock#readLock}. */ 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); } /** * Acquires the read lock unless the current thread is * {@linkplain Thread#interrupt interrupted}. * * <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 one of two things happens: * * <ul> * * <li>The read lock is acquired by the current thread; or * * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. * * </ul> * * <p>If the current thread: * * <ul> * * <li>has its interrupted status set on entry to this method; or * * <li>is {@linkplain Thread#interrupt interrupted} while * acquiring the read lock, * * </ul> * * then {@link InterruptedException} is thrown and the current * thread's interrupted status is cleared. * * <p>In this implementation, as this method is an explicit * interruption point, preference is given to responding to * the interrupt over normal or reentrant acquisition of the * lock. * * @throws InterruptedException if the current thread is interrupted */ public void lockInterruptibly() throws InterruptedException { sync.acquireSharedInterruptibly(1); } /** * Acquires the read lock only if the write lock is not held by * another thread at the time of invocation. * * <p>Acquires the read lock if the write lock is not held by * another thread and returns immediately with the value * {@code true}. Even when this lock has been set to use a * fair ordering policy, a call to {@code tryLock()} * <em>will</em> immediately acquire the read lock if it is * available, whether or not other threads are currently * waiting for the read lock. This "barging" behavior * can be useful in certain circumstances, even though it * breaks fairness. If you want to honor the fairness setting * for this lock, then use {@link #tryLock(long, TimeUnit) * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent * (it also detects interruption). * * <p>If the write lock is held by another thread then * this method will return immediately with the value * {@code false}. * * @return {@code true} if the read lock was acquired */ public boolean tryLock() { return sync.tryReadLock(); } /** * Acquires the read lock if the write lock is not held by * another thread within the given waiting time and the * current thread has not been {@linkplain Thread#interrupt * interrupted}. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -