美文网首页并发和多线程
2020-02-03 2.2.4 读写锁 ReadWriteLo

2020-02-03 2.2.4 读写锁 ReadWriteLo

作者: FredWorks | 来源:发表于2020-02-03 18:06 被阅读0次

    本文是Java线程安全和并发编程知识总结的一部分。

    2.2.4 读写锁

    ReentrantLock实现的是一种标准的互斥锁,每次只允许一个线程获得锁操作。而现实中,大部分业务操作都是读操作多余写操作。只要确保多个线程可以读取到最新的数据,且期间不会有其他线程修改数据,那么实际上多个线程同时读,是不会引发业务上的冲突的。此时,并发性能会比RentrantLock更高。
    实现这个意图的锁就是ReadWriteLock及其实现ReentrantReadWriteLock

    • 读写锁允许单独获取读锁和写锁。
    • 读锁允许多个线程同时申请并获得,从而实现多线程读。
    • 写锁只允许一个线程获得,从而确保只有一个线程在写。

    需要说明的是:

    • ReadWriteLock 并未说明读锁和写锁是否是可重入锁。但ReentrantReadWriteLock是可重入锁实现。
    • ReadWriteLock 对锁获取插队问题没有规定。ReentrantReadWriteLock为公平锁时,不允许插队;为非公平锁时允许读锁插队到写锁而将写锁降级为读锁,但不允许写锁插队到读锁从而将读锁升级为写锁。

    大体上而言,读写锁是否一定能提升性能?这个需要区分场景分析:

    • 如果一个任务中,读操作远远大于写操作,那么读写锁性能提升是明显的。
    • 如果一个任务中,读写操作的耗时大体相当,甚至写多余读,那么读写锁基本不会有什么性能提升。

    需要注意的是:

    • 使用读写锁的代码是否会发生脏写,并不由读写锁代码本身控制,而是由使用读写锁的业务代码决定。假如一个线程在执行读操作时,有另外一个线程执行写操作了,那么读线程可能会读取到脏数据的。

    下面是一个封装普通ArrayList使其读并发写串行的例子:

    /**
     * @author xx
     * 2020年2月3日 下午6:02:32 xx添加此方法
     */
    public class ReadWriteLockArrayList<T> extends ArrayList<T> {
        
        private static final long serialVersionUID = 5764776949955586441L;
    
        private final ReadWriteLock lock = new ReentrantReadWriteLock();
        
        private final Lock readLock = this.lock.readLock();
        
        private final Lock writeLock = this.lock.writeLock();
        
        private ArrayList<T> list;
        
        /**
         * 构造函数
         */
        public ReadWriteLockArrayList(int initialCapacity) {
            this.list = new ArrayList<T>(initialCapacity);
        }
        
        /**
         * 构造函数
         */
        public ReadWriteLockArrayList() {
            this.list = new ArrayList<T>();
        }
        
        /**
         * 构造函数
         */
        public ReadWriteLockArrayList(Collection<T> c) {
            this.list = new ArrayList<T>(c);
        }
    
        /**
         * 读操作,加读锁
         * 参看父类中的注释 @see java.util.ArrayList#get(int)
         * 2020年2月3日 下午6:02:32 xx添加此方法
         */
        public T get(int index) {
            this.readLock.lock();
            try {
                return this.list.get(index);
            } finally {
                this.readLock.unlock();
            }
        }
    
        /**
         * 写操作,加写锁
         * 参看父类中的注释 @see java.util.ArrayList#add(E e)
         * 2020年2月3日 下午6:02:32 xx添加此方法
         * @param e
         * @return
         */
        public boolean add(T e) {
            this.writeLock.lock();
            try {
                return this.list.add(e);
            } finally {
                this.writeLock.unlock();
            }
        }
        
        /**
         * 写操作,加写锁
         * 参看父类中的注释 @see java.util.ArrayList#trimToSize()
         * 2020年2月3日 下午6:02:32 xx添加此方法
         */
        public void trimToSize() {
            this.writeLock.lock();
            try {
                this.list.trimToSize();
            } finally {
                this.writeLock.unlock();
            }
        }
        
        /*
         * 其他操作类似上述行为
         */
    }
    

    相关文章

      网友评论

        本文标题:2020-02-03 2.2.4 读写锁 ReadWriteLo

        本文链接:https://www.haomeiwen.com/subject/juqkxhtx.html