ReentrantReadWritelock是ReadWrite的一个实现类,与ReentrantLock有着相似的语法。
A)Acquisition Order 该类并不强制读锁或者写锁按照优先级进行获取,但是它提供可供选择的公平策略。
Non-fair mode:默认情况下,采用的是非公平策略,读锁和写锁并未明确入队顺序,其受限于可重入约束性。持续竞争的锁可能会使一个或者多个线程无法获得该锁,但是其在吞吐量上明显优于公平策略的锁。
Fair mode:采用公平策略的锁,会保证竞争的线程尽量按照到达先后的顺序进行入队。当当前线程释放锁的时候,等待队列中等待时间最长的写线程将会被唤醒;或者等待时间更长的一组读线程将会被唤醒。
如果写锁被其他线程持有,或者等待队列中有写线程,获取公平读锁的线程会被阻塞。当等待时间最长的写线程获得该锁然后释放后,读线程才会获得该读锁。当然,如果等待的写线程被取消了,等待队列中不存在写线程,则等待的读线程将会被分配读锁。
只有在读锁和写锁未被持有的情况下,写线程才可以成功获取写锁。WriterLock和ReaderLock的tryLock()与ReentrantLock的tryLock()相似,如果成功获取锁直接返回,无论等待队列是否为null。
B)Reentrancy 无论读锁还是写锁都支持可重入性。只有当写锁被释放的时候,读线程才有机会获取锁。另外,一个写线程可以获取读锁,反之不可以。在其他应用方面,持有写锁的线程调用读锁的方法,,可重入性是非常有用的。如果一个持有读锁的线程获取写锁,将不会成功。
C)Lock downgrading(锁降级) 当获取写锁的时候,可重入性允许写锁降级为读锁,然后获取读锁,再释放写锁。然后,读锁是不可以更新为写锁的 。
D)Interruption of Lock Acquisition 读锁与写锁在获取锁的过程中支持中断机制。
E)Condition Support 写锁支持Condition,但是读锁不支持。如果ReadLock.new Condition,将会抛出异常。
F)Instrumentation 该类提供了一些方法来检查锁的状态。这些方法并不是用来做同步控制。
同样的,该类是可序列化的,与ReentrantLock相似。
For example
class CachedData { * Object data; * volatile boolean cacheValid; * final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); * void processCachedData() { * rwl.readLock().lock(); * if (!cacheValid) { * // Must release read lock before acquiring write lock * rwl.readLock().unlock(); * rwl.writeLock().lock(); * try { * // Recheck state because another thread might have * // acquired write lock and changed state before we did. * if (!cacheValid) { * data = ... * cacheValid = true; * } * // Downgrade by acquiring read lock before releasing write lock * rwl.readLock().lock(); * } finally { * rwl.writeLock().unlock(); // Unlock write, still hold read * } * } * * try { * use(data); * } finally { * rwl.readLock().unlock(); * } * } * }} |
ReentrantReadWriteLock可以用在一些集合类中用来改善并发情况。读写锁主要应用于读多写少的情景。
For example the using of TreeMap
class RWDictionary { * private final Map<String, Data> m = new TreeMap<String, Data>(); * private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); * private final Lock r = rwl.readLock(); * private final Lock w = rwl.writeLock(); * * public Data get(String key) { * r.lock(); * try { return m.get(key); } * finally { r.unlock(); } * } * public String[] allKeys() { * r.lock(); * try { return m.keySet().toArray(); } * finally { r.unlock(); } * } * public Data put(String key, Data value) { * w.lock(); * try { return m.put(key, value); } * finally { w.unlock(); } * } * public void clear() { * w.lock(); * try { m.clear(); } * finally { w.unlock(); } * } * }} |
该锁中,读锁的数量和写锁的数量的最大值均为65535。因为state是一个int,前2个字节(16位)代表写锁,后四个字节(16位)代表读锁,均为。
1 WriteLock
1.1 Lock()
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); |
1.1.1 trayAcquire[a1] ()
1.存在读锁或者 存在写锁并且持有该锁的线程非本线程,return false;
2.存在写锁并且该线程持有该锁,则检查写锁的count,if count>MAX_COUNT, throw exception;
3.否则,count=0,线程开始竞争该锁:检查是否需要阻塞(非公平锁不需要阻塞,公平锁需要检查是否存在前继节点);不阻塞话,进行CAS设置state。如果OK的话,设置该锁的线程为本线程。
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) 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; } if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false; setExclusiveOwnerThread(current); return true; } |
1.1.2 addWaiter()
同AQS |
1.1.3 acquireQueued()
同AQS |
1.2 tryLock()
sync.tryWriteLock(); |
1.2.1 tryWriteLock()
与trayAcquire相比,lack of the function - 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; } |
1.3 tryLock(long timeout, TimeUnit unit)
return sync.tryAcquireNanos(1, unit.toNanos(timeout)); |
1.3.1 tryAcquireNanos(int arg, long nanosTimeout)
if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout); |
1.3.1.1 doAcquireNanos(int arg, long nanosTimeout)
增加一个时间节点的判断
if (nanosTimeout <= 0L) return false; final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return true; } nanosTimeout = deadline - System.nanoTime(); if (nanosTimeout <= 0L) return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); if (Thread.interrupted()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } |
1.4 unlock()
sync.release(1); 同AQS |
1.5 Release()
如果本线程成功释放锁,则会判断是否存在后继节点。如果存在并且head的waitstatus!=0则唤醒后继节点中的线程。
if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; |
1.5.1 tryRelease()
如果该线程不持有该锁,释放该锁,抛出illegalMonitorStateException;
释放锁后,判断state的写锁的数量是否为0,如果为0,则独占锁=null,否则该线程继续持有该锁。
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; } |
1.5.2 unparkSuccessor()[a2]
如果头结点head.waitStatus小于0,则CAS其status为0(初始状态);
遍历循环同步队列,查询距离head最近的waitStatus<=0的结点,唤醒该结点的thread。
waitStatus>0(cancelled)。
同AQS private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); } |
2 ReadLock
2.1 Lock()
sync.acquireShared(1); |
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); } |
2.1.1 tryAcquireShared[a3] ()
1.如果写锁被其他线程持有,return false;
2.是否阻塞,分公平与非公平两种策略。
如果是非公平,为了防止写线程饥饿,如果同步队列中的第一个节点为写线程,则进行阻塞。如果是公平,则判断是否是第一个节点。
3.如果不阻塞,则Cas state。
如果开始不存在读锁,则count=1;
如果firstReader=current,则count++;
否则,缓存cachedHoldCounter
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); } |
2.1.1.1 NofairSync.readerShouldBlock()
非公平,为了防止写线程饥饿,如果同步队列中的第一个节点为写线程,则进行阻塞。
return apparentlyFirstQueuedIsExclusive(); |
final boolean apparentlyFirstQueuedIsExclusive() { Node h, s; return (h = head) != null && (s = h.next) != null && !s.isShared() && s.thread != null; } |
2.1.1.2 FairSync.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()); } |
2.1.1.3 fullTryAcquireShared(Thread 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(); 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; } } } |
2.1.2 doAcquireShared(int arg)
同 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); } } |
2.2 tryLock()
return sync.tryReadLock(); |
2.2.1 tryReadLock()
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; } } } |
2.3 Unlock
public void unlock() { sync.releaseShared(1); } |
2.4 releaseShared(int arg)
public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false; } |
2.4.1 tryReleaseShared()
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; } } |
2.4.2 doRelease[a4] Shared()
private void doReleaseShared() { 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; } } |