并发编程之ReadWriteLock读写锁

Posted 沸羊羊一个

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程之ReadWriteLock读写锁相关的知识,希望对你有一定的参考价值。

1、前言
ReadWriteLock是jdk5中提供得读写分离锁。读写分离锁可以有效地帮助减少锁竞争,以提高系统性能。
在实际应用中,如果读操作次数远大于写操作,则读写锁就可以发挥最大得功效,提升系统性能。

- 读读不互斥:读读之间不阻塞
- 读写互斥:读阻写,写也会阻读
- 写写互斥:写写阻塞

2、使用��
package package3;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读读(非阻塞)、读写(阻塞)、写写(阻塞)
 *
 * 以下demo,不用读写锁,要花费20秒。 使用读写锁,远小于花费20秒
 */
public class ReadWriteLockDemo 
    private static Lock lock = new ReentrantLock();
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();//实例化读写锁
    private static Lock readLock = readWriteLock.readLock();//获取读锁
    private static Lock writeLock = readWriteLock.writeLock();//获取写锁

    private int value;

    public int handleRead(Lock lock)
        try
            lock.lock();//模拟读操作
            Thread.sleep(1000);//模拟耗时
        catch (Exception e)
            e.printStackTrace();
        finally 
            lock.unlock();

        
        return this.value;
    

    public void handleWrite(Lock lock,int index)
        try
            lock.lock();
            Thread.sleep(1000);
            this.value = index;
        catch (Exception e)
            e.printStackTrace();
        finally 
            lock.unlock();
        
    

    public static void main(String[] args) 
        final ReadWriteLockDemo readWriteLockDemo = new ReadWriteLockDemo();

        //读线程
        Runnable readRunable = new Runnable() 
            @Override
            public void run() 
                readWriteLockDemo.handleRead(readLock);
               // readWriteLockDemo.handleRead(lock);
            
        ;

        //写线程
        Runnable writeRunable = new Runnable() 
            @Override
            public void run() 
                readWriteLockDemo.handleWrite(writeLock,new Random().nextInt(1000));
                //readWriteLockDemo.handleWrite(lock,new Random().nextInt(1000));
            
        ;

        for (int i=0;i<18;i++)
            new Thread(readRunable).start();
        

        for (int i=18;i<20;i++)
            new Thread(writeRunable).start();
        
    

由于采用读写锁,读读之间并行,节省了大量实际。整个程序大约2秒运行完成。如果不采用读写锁,程序执行将长达20秒。

3、Java并发-ReentrantReadWriteLock源码分析
4、ReentrantReadWriteLock源码

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;


public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable 
    private static final long serialVersionUID = -6992448646407690164L;
    /** 内部类读锁 */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** 内部类写锁 */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    /** 同步机制类 */
    final Sync sync;

    /**
     *构造函数,默认不公平锁
     */
    public ReentrantReadWriteLock() 
        this(false);
    

    /**
     * 构造函数
     * @param fair 是否公平锁  true:公平  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; 

    /**
     * reentrantreadwritelock同步的实现。
     * 定义为公平和不公平两版本。
     */
    abstract static class Sync extends AbstractQueuedSynchronizer 
        private static final long serialVersionUID = 6317671515068378041L;

        /*
         * 读写锁中最重要的就是Sync类,它继承自AQS。AQS使用一个int型来保存状态,状态在这里就代表锁,它提供了获取和修改状态的方法。
         * 状态的高16位用作读锁(共享锁方式),低16位用作写锁(独占锁方式)
         */

        //最多支持65535个写锁和65535个读锁;低16位表示写锁计数,高16位表示持有读锁的线程数
        static final int SHARED_SHIFT   = 16;
        //由于读锁用高位部分,读锁个数加1,其实是状态值加 2^16
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        /**写锁的掩码,用于状态的低16位有效值 */
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /** 读锁(共享锁)计数,当前持有读锁的线程数,c的高16位 */
        static int sharedCount(int c)     return c >>> SHARED_SHIFT; 
        /** 写锁(独占锁)的计数,也就是它的重入次数,c的低16位*/
        static int exclusiveCount(int c)  return c & EXCLUSIVE_MASK; 

        /**
         * 每个线程持有读锁的计数
         */
        static final class HoldCounter 
            int count = 0;
            //使用id而不是引用是为了避免保留垃圾。注意这是个常量。
            final long tid = getThreadId(Thread.currentThread());
        

        /**
         * 采用继承是为了重写 initialValue 方法,这样就不用进行这样的处理:
         * 如果ThreadLocal没有当前线程的计数,则new一个,再放进ThreadLocal里。
         * 可以直接调用 get。
         * */
        static final class ThreadLocalHoldCounter
                extends ThreadLocal<HoldCounter> 
            public HoldCounter initialValue() 
                return new HoldCounter();
            
        

        /**
         * 当前线程持有的可重入读锁的数量,仅在构造方法和readObject(反序列化)
         * 时被初始化,当持有锁的数量为0时,移除此对象。
         */
        private transient ThreadLocalHoldCounter readHolds;

        /**
         * 最近一个成功获取读锁的线程的计数。这省却了ThreadLocal查找,
         * 通常情况下,下一个释放线程是最后一个获取线程。这不是 volatile 的,
         * 因为它仅用于试探的,线程进行缓存也是可以的
         * (因为判断是否是当前线程是通过线程id来比较的)。
         */
        private transient HoldCounter cachedHoldCounter;


        /**firstReader是第一个获得读锁的线程;
         * firstReaderHoldCount是firstReader的重入计数;
         * 更准确的说,firstReader是最后一个把共享计数从0改为1,并且还没有释放锁。
         * 如果没有这样的线程,firstReader为null;
         * firstReader不会导致垃圾堆积,因为在tryReleaseShared中将它置空了,除非
         * 线程异常终止,没有释放读锁。
         *
         * 跟踪无竞争的读锁计数时,代价很低
         */
        private transient Thread firstReader = null;
        private transient int firstReaderHoldCount;

        Sync() 
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        

        /**
         * 读锁是否需要阻塞
         */
        abstract boolean readerShouldBlock();

        /**
         * 写锁是否需要阻塞
         */
        abstract boolean writerShouldBlock();

        /**
         * 释放写锁
         */
        protected final boolean tryRelease(int releases) 
            if (!isHeldExclusively())//当前线程没有持有锁,抛异常
                throw new IllegalMonitorStateException();
            //获得一次锁,同步状态+1,释放时每释放一次同步状态-1,直到状态为0,可重入锁全部释放完毕。
            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) //说明存在锁,可能是读锁,也可能是写锁
                // (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");

                //执行到这里,说明存在写锁,且由当前线程持有
                // 重入计数
                setState(c + acquires);
                return true;
            

            //执行到这里,说明不存在任何锁
            //WriterShouldBlock留给子类实现公平策略
            //使用CAS修改状态
            if (writerShouldBlock() ||
                    !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        

        /**
         * 释放读锁
         */
        protected final boolean tryReleaseShared(int unused) 
            Thread current = Thread.currentThread();//获取当前线程
            /**
             * 当前线程是第一个获取到锁的,如果此线程要释放锁了,则firstReader置空
             * 否则,将线程持有的锁计数减1
             */
            if (firstReader == current) 
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
             else 
                HoldCounter rh = cachedHoldCounter;
                //如果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))
                    // 释放读锁对其他读线程没有任何影响,
                    // 但可以允许等待的写线程继续,如果读锁、写锁都空闲。
                    return nextc == 0;
            
        

        private IllegalMonitorStateException unmatchedUnlockException() 
            return new IllegalMonitorStateException(
                    "attempt to unlock read lock, not locked by current thread");
        

        //Sync中的tryAcquireShared  尝试获取读锁
        protected final int tryAcquireShared(int unused) 
            /*
            (1)如果当前写锁被其他线程持有,则获取读锁失败;
            (2)写锁空闲,或者写锁被当前线程持有(写锁可降级为读锁),在公平策略下,它可能需要阻塞,那么tryAcquireShared()就可能失败,则需要进入队列等待;
                如果是非公平策略,会尝试获取锁,使用CAS修改状态,修改成功,则获得读锁,否则也会进入同步队列等待;
            (3)进入同步队列后,就是由AQS来完成唤醒。
            */
            Thread current = Thread.currentThread();//获取当前线程
            int c = getState();//同步获取状态
            /*** 持有写锁的线程可以获得读锁 **/
            if (exclusiveCount(c) != 0 &&            //写锁被占用
                    getExclusiveOwnerThread() != current) //且不是由当前线程持有
                return -1;

            /******** 执行到这里表明:写锁可用,或者写锁由当前线程持有   *****/
            //获得读锁的数量
            int r = sharedCount(c);
            /** 如果读锁没有阻塞,且没有溢出,则使用CAS修改状态,并且修改成功 */
            if (!readerShouldBlock() &&
                    r < MAX_COUNT &&
                    compareAndSetState(c, c + SHARED_UNIT)) //修改高16位的状态,所以要加上2^16
                //这是第一个占有读锁的线程,所以设置firstReader
                if (r == 0) 
                    firstReader = current;
                    firstReaderHoldCount = 1;
                 else if (firstReader == current) 
                    firstReaderHoldCount++;//重入计数加1
                 else 
                    // 非 firstReader 读锁重入计数更新
                    //将cachedHoldCounter设置为当前线程
                    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);
        

        /**
         * 处理读写失败的完整读取版本
         * 和tryacquireshared不同在于,此方法循环获取锁
         */
        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) 
                            //将cachedHoldCounter设置为当前线程
                            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)) //修改高16位的状态,所以要加上2^16
                    //这是第一个占有读锁的线程,所以设置firstReader
                    if (sharedCount(c) == 0) 
                        firstReader = current;
                        firstReaderHoldCount = 1;
                     else if (firstReader == current) //重入计数加1
                        firstReaderHoldCount++;
                     else 
                        // 非 firstReader 读锁重入计数更新
                        //将cachedHoldCounter设置为当前线程
                        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;
                
            
        

        /**
         * 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;
                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();
        

        // 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() 
            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;
        

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        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() 
            /* 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 probabilistic 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();
        
    

    /**
     * 公平同步锁
     */
    static final class FairSync extends Sync 
        private static final long serialVersionUID = -2274990926593161451L;
        final boolean writerShouldBlock() 
            return hasQueuedPredecessors();
        
        final boolean readerShouldBlock() 
            return hasQueuedPredecessors();
        
    

    /**
     * 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;
        

        /**
         * 获取读锁,如果写锁不是由其他线程持有,则获取并立即返回;
         * 如果写锁被其他线程持有,阻塞,直到读锁被获得。
         */
        public void lock() 
            sync.acquireShared(1);
            //ASQ的acquireShared
            /**
             * 以共享模式获取对象,忽略中断。通过至少先调用一次 tryAcquireShared(int)
             * 来实现此方法,并在成功时返回。否则在成功之前,一直调用 tryAcquireShared(int)
             *  将线程加入队列,线程可能重复被阻塞或不被阻塞。
             */
            /*public final void acquireShared(int arg) 
                if (tryAcquireShared(arg) < 0)
                    doAcquireShared(arg);
            */
        

        /**
         * 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 &quot;barging&quot; 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.
         *
         * <p>Acquires the read lock if the write lock is not held by
         * another thread and returns immediately with the value
         * @code true. If this lock has been set to use a fair
         * ordering policy then an available lock <em>will not</em> be
         * acquired if any other threads are waiting for the
         * lock. This is in contrast to the @link #tryLock()
         * method. If you want a timed @code tryLock that does
         * permit barging on a fair lock then combine the timed and
         * un-timed forms together:
         *
         *  <pre> @code
         * if (lock.tryLock() ||
         *     lock.tryLock(timeout, unit)) 
         *   ...
         * </pre>
         *
         * <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 three 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; or
         *
         * <li>The specified waiting time elapses.
         *
         * </ul>
         *
         * <p>If the read lock is acquired then the value @code true is
         * returned.
         *
         * <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>If the specified waiting time elapses then the value
         * @code false is returned.  If the time is less than or
         * equal to zero, the method will not wait at all.
         *
         * <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, and over reporting the elapse of the waiting time.
         *
         * @param timeout the time to wait for the read lock
         * @param unit the time unit of the timeout argument
         * @return @code true if the read lock was acquired
         * @throws InterruptedException if the current thread is interrupted
         * @throws NullPointerException if the time unit is null
         */
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException 
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
        

        /**
         * Attempts to release this lock.
         *
         * <p>If the number of readers is now zero then the lock
         * is made available for write lock attempts.
         */
        public void unlock() 
            sync.releaseShared(1);
        

        /**
         * Throws @code UnsupportedOperationException because
         * @code ReadLocks do not support conditions.
         *
         * @throws UnsupportedOperationException always
         */
        public Condition newCondition() 
            throw new UnsupportedOperationException();
        

        /**
         * Returns a string identifying this lock, as well as its lock state.
         * The state, in brackets, includes the String @code "Read locks ="
         * followed by the number of held read locks.
         *
         * @return a string identifying this lock, as well as its lock state
         */
        public String toString() 
            int r = sync.getReadLockCount();
            return super.toString() +
                    "[Read locks = " + r + "]";
        
    

    /**
     * The lock returned by method @link ReentrantReadWriteLock#writeLock.
     */
    public static class WriteLock implements Lock, java.io.Serializable 
        private static final long serialVersionUID = -4992448646407690164L;
        private final Sync sync;

        /**
         * Constructor for use by subclasses
         *
         * @param lock the outer lock object
         * @throws NullPointerException if the lock is null
         */
        protected WriteLock(ReentrantReadWriteLock lock) 
            sync = lock.sync;
        

        /**
         * Acquires the write lock.
         *
         * <p>Acquires the write lock if neither the read nor write lock
         * are held by another thread
         * and returns immediately, setting the write lock hold count to
         * one.
         *
         * <p>If the current thread already holds the write lock then the
         * hold count is incremented by one and the method returns
         * immediately.
         *
         * <p>If the lock is held by another thread then the current
         * thread becomes disabled for thread scheduling purposes and
         * lies dormant until the write lock has been acquired, at which
         * time the write lock hold count is set to one.
         */
        public void lock() 
            sync.acquire(1);
        

        /**
         * Acquires the write lock unless the current thread is
         * @linkplain Thread#interrupt interrupted.
         *
         * <p>Acquires the write lock if neither the read nor write lock
         * are held by another thread
         * and returns immediately, setting the write lock hold count to
         * one.
         *
         * <p>If the current thread already holds this lock then the
         * hold count is incremented by one and the method returns
         * immediately.
         *
         * <p>If the 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 write lock is acquired by the current thread; or
         *
         * <li>Some other thread @linkplain Thread#interrupt interrupts
         * the current thread.
         *
         * </ul>
         *
         * <p>If the write lock is acquired by the current thread then the
         * lock hold count is set to one.
         *
         * <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 write 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.acquireInterruptibly(1);
        

        /**
         * Acquires the write lock only if it is not held by another thread
         * at the time of invocation.
         *
         * <p>Acquires the write lock if neither the read nor write lock
         * are held by another thread
         * and returns immediately with the value @code true,
         * setting the write lock hold count to one. Even when this lock has
         * been set to use a fair ordering policy, a call to
         * @code tryLock() <em>will</em> immediately acquire the
         * lock if it is available, whether or not other threads are
         * currently waiting for the write lock.  This &quot;barging&quot;
         * 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 current thread already holds this lock then the
         * hold count is incremented by one and the method returns
         * @code true.
         *
         * <p>If the lock is held by another thread then this method
         * will return immediately with the value @code false.
         *
         * @return @code true if the lock was free and was acquired
         * by the current thread, or the write lock was already held
         * by the current thread; and @code false otherwise.
         */
        public boolean tryLock( ) 
            return sync.tryWriteLock();
        

        /**
         * Acquires the write lock if it is not held by another thread
         * within the given waiting time and the current thread has
         * not been @linkplain Thread#interrupt interrupted.
         *
         * <p>Acquires the write lock if neither the read nor write lock
         * are held by another thread
         * and returns immediately with the value @code true,
         * setting the write lock hold count to one. If this lock has been
         * set to use a fair ordering policy then an available lock
         * <em>will not</em> be acquired if any other threads are
         * waiting for the write lock. This is in contrast to the @link
         * #tryLock() method. If you want a timed @code tryLock
         * that does permit barging on a fair lock then combine the
         * timed and un-timed forms together:
         *
         *  <pre> @code
         * if (lock.tryLock() ||
         *     lock.tryLock(timeout, unit)) 
         *   ...
         * </pre>
         *
         * <p>If the current thread already holds this lock then the
         * hold count is incremented by one and the method returns
         * @code true.
         *
         * <p>If the lock is held by another thread then the current
         * thread becomes disabled for thread scheduling purposes and
         * lies dormant until one of three things happens:
         *
         * <ul>
         *
         * <li>The write lock is acquired by the current thread; or
         *
         * <li>Some other thread @linkplain Thread#interrupt interrupts
         * the current thread; or
         *
         * <li>The specified waiting time elapses
         *
         * </ul>
         *
         * <p>If the write lock is acquired then the value @code true is
         * returned and the write lock hold count is set to one.
         *
         * <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 write lock,
         *
         * </ul>
         *
         * then @link InterruptedException is thrown and the current
         * thread's interrupted status is cleared.
         *
         * <p>If the specified waiting time elapses then the value
         * @code false is returned.  If the time is less than or
         * equal to zero, the method will not wait at all.
         *
         * <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, and over reporting the elapse of the waiting time.
         *
         * @param timeout the time to wait for the write lock
         * @param unit the time unit of the timeout argument
         *
         * @return @code true if the lock was free and was acquired
         * by the current thread, or the write lock was already held by the
         * current thread; and @code false if the waiting time
         * elapsed before the lock could be acquired.
         *
         * @throws InterruptedException if the current thread is interrupted
         * @throws NullPointerException if the time unit is null
         */
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException 
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        

        /**
         * Attempts to release this lock.
         *
         * <p>If the current thread is the holder of this lock then
         * the hold count is decremented. If the hold count is now
         * zero then the lock is released.  If the current thread is
         * not the holder of this lock then @link
         * IllegalMonitorStateException is thrown.
         *
         * @throws IllegalMonitorStateException if the current thread does not
         * hold this lock
         */
        public void 以上是关于并发编程之ReadWriteLock读写锁的主要内容,如果未能解决你的问题,请参考以下文章

Java——多线程高并发系列之ReadWriteLock读写锁

并发编程系列之ReadWriteLock使用

并发编程系列之ReadWriteLock使用

一种比读写锁更快的锁,还不赶紧认识一下

深入理解读写锁—ReadWriteLock源码分析

java并发:读写锁ReadWriteLock