java.util.concurrent.locks包中的ReentrantReadWriteLock

ReentrantReadWritelock ReadWrite is an implementation class, and ReentrantLock has a similar syntax.

A) Acquisition the Order class is not mandatory to write lock or read lock acquisition in accordance with the priorities, but it offers a fair alternative strategies.

Non-fair mode: By default, non-equity strategies used to read and write locks did not explicitly order into the team, which is limited by the reentrant binding. Sustainable competitive locks may make one or more threads can not get the lock, but it is superior to lock fairness policy on throughput.

Fair mode: using lock fairness policy, will ensure that competition in the thread as far as possible into the team has in the order of arrival. When the current thread releases the lock when waiting in the queue waiting for the longest time writing thread will be awakened; or wait longer to read a set of thread will be awakened.

If the write lock is held by another thread, or wait in the queue write thread, a thread get a fair read lock will be blocked. After waiting the longest to write thread to acquire the lock and then release, the reader thread will get a read lock. Of course, if you wait for the write thread was canceled, there is no thread is waiting for a write queue, waiting to read the thread will be assigned a read lock.

Only in the case of read and write locks are not held by the writing thread can successfully obtain a write lock. WriterLock and ReaderLock of tryLock () and ReentrantLock of tryLock () Similarly, if the lock is successfully acquired direct return, regardless of whether the queue is null.

B) reentrancy whether a read lock or a write lock support reentrancy. Only when the write lock is released, and have a chance to read a thread acquires the lock. In addition, a write thread can acquire a read lock, not vice versa. In other applications, has the write lock thread calls the method read lock ,, reentrancy is very useful. If a thread that holds a read lock acquire write locks, will not succeed.

C) Lock downgrading ( degrade lock) when the acquired write lock when reentrancy write lock allow downgraded to a read lock, then acquire the read lock, then releases the write lock. Then, read lock is not updated to the write lock.

D) Interruption of Lock Acquisition read locks and write locks support interrupt mechanism in the process of acquiring the lock.

E) for condition Condition Support write locks support Condition, but read locks are not supported. If ReadLock.new Condition, will throw an exception.

F.) The Instrumentation class provides the method to check the state of the lock. These methods are not used for synchronization control.

 

Similarly, the class is serializable with ReentrantLock similar.

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 may be used in a collection of classes to improve concurrency. Read-write lock are mainly used to write little scene.

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;

        }

    }

 


Guess you like

Origin www.cnblogs.com/charging-for-ycp/p/11432602.html