zoukankan      html  css  js  c++  java
  • 同步锁 —— ReentrantReadWriteLock

    本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。

    并发编程系列博客传送门

    本文是转债文章,原文见博客

    ReadWriteLock接口简介

    ReadWriteLock接口是一个单独的接口(未继承Lock接口),该接口提供了获取读锁和写锁的方法。

    所谓读写锁,是一对相关的锁——读锁和写锁,读锁用于只读操作,写锁用于写入操作。读锁可以由多个线程同时保持,而写锁是独占的,只能由一个线程获取。

    接口内容

    public interface ReadWriteLock {
        /**
         * Returns the lock used for reading.
         *
         * @return the lock used for reading
         */
        Lock readLock();
    
        /**
         * Returns the lock used for writing.
         *
         * @return the lock used for writing
         */
        Lock writeLock();
    }
    

    由于读写锁本身的实现就远比独占锁复杂,因此,读写锁比较适用于以下情形:

    1. 高频次的读操作,相对较低频次的写操作
    2. 读操作所用时间不会太短。(否则读写锁本身的复杂实现所带来的开销会成为主要消耗成本)

    ReentrantReadWriteLock简介

    ReentrantReadWriteLock类,顾名思义,是一种读写锁,它是ReadWriteLock接口的直接实现,该类在内部实现了具体独占锁特点的写锁,以及具有共享锁特点的读锁,和ReentrantLock一样,ReentrantReadWriteLock类也是通过定义内部类实现AQS框架的API来实现独占/共享的功能。

    ReentrantReadWriteLock类具有如下特点:

    支持公平/非公平策略

    与ReadWriteLock类一样,ReentrantReadWriteLock对象在构造时,可以传入参数指定是公平锁还是非公平锁。

     /**
         * Creates a new {@code ReentrantReadWriteLock} with
         * default (nonfair) ordering properties.
         */
        public ReentrantReadWriteLock() {
            this(false);
        }
    
        /**
         * Creates a new {@code ReentrantReadWriteLock} with
         * the given fairness policy.
         *
         * @param fair {@code true} if this lock should use a fair ordering policy
         */
        public ReentrantReadWriteLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
            readerLock = new ReadLock(this);
            writerLock = new WriteLock(this);
        }
    

    支持锁重入

    • 同一读线程在获取了读锁后还可以获取读锁;
    • 同一写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;

    支持锁降级

    所谓锁降级,就是:先获取写锁,然后获取读锁,最后释放写锁,这样写锁就降级成了读锁。但是,读锁不能升级到写锁。简言之,就是:

    写锁可以降级成读锁,读锁不能升级成写锁。

    Condition条件支持

    ReentrantReadWriteLock的内部读锁类、写锁类实现了Lock接口,所以可以通过newCondition()方法获取Condition对象。但是这里要注意,读锁是没法获取Condition对象的,读锁调用newCondition() 方法会直接抛出UnsupportedOperationException

    我们知道,condition的作用其实是对Object类的wait()notify()的增强,是为了让线程在指定对象上等待,是一种线程之间进行协调的工具。
    当线程调用condition对象的await方法时,必须拿到和这个condition对象关联的锁。由于线程对读锁的访问是不受限制的(在写锁未被占用的情况下),那么即使拿到了和读锁关联的condition对象也是没有意义的,因为读线程之前不需要进行协调。

    使用示例

    以下是Oracle官方给出的一个例子:
    使用ReentrantReadWriteLock控制对TreeMap的访问(利用读锁控制读操作的访问,利用写锁控制修改操作的访问),将TreeMap包装成一个线程安全的集合,并且利用了读写锁的特性来提高并发访问。

    public class RWTreeMap {
        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 (String[]) 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();
            }
        }
    }
    

    参考

    https://blog.csdn.net/sinat_36572927/article/details/90242379

    https://cloud.tencent.com/developer/article/1461980

  • 相关阅读:
    wes7配置
    一个很牛逼的工具XueTr
    构造一个好控制一点的长期工作线程
    SmartGit初步使用
    Android开发(一):环境搭建
    zabbix使用短信猫实现报警
    Build Libsvm to dll
    Using OpenCV in VS2012
    My Overlay Icons is Missing
    用Eclipse开发C、C++
  • 原文地址:https://www.cnblogs.com/54chensongxia/p/12674359.html
Copyright © 2011-2022 走看看