zoukankan      html  css  js  c++  java
  • 廖雪峰Java11多线程编程-3高级concurrent包-2ReadWriteLock

    1.ReentrantLock的限制

    ReentrantLock保证了只有一个线程可以执行临界区代码。
    临界区代码:任何时候只有1个线程可以执行的代码块。
    临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。

    public void inc(){    
        lock.lock();
        try{
            value += 1;
        }finally{
            lock.unlock();
        }
    }
    public int get(){    
        lock.lock();
        try(){
            return value;
        }finally{
            lock.unlock();
        }
    }
    

    但有时候,这种保护有些过头:

    • 因为我们发现任何时刻只允许1个线程修改,对inc()进行加锁是必须的。
    • 但是get()方法只读取数据,不修改数据。它应该允许多个线程同时调用。

    我们期望:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。

    2. ReadWriteLock

    使用ReadWriteLock可以解决:

    • 只允许一个线程写入(其他线程既不能写入,也不能读取)
    • 没有写入时,多个线程允许同时读(提高性能)
    • 实现
    class Counter{
        final ReadWriteLock lock = new ReentrantReadWriteLock();
        //分别获得readLock和writeLock
        final Lock rlock = lock.readLock();
        final Lock wlock = lock.writeLock();
        private int value = 0;
        public void inc(){
            wlock.lock();
            try{
                value += 1;
            }finally {
                wlock.unlock();
            }
        }
        public int get(){
            rlock.lock();
            try{
                return this.value;
            }finally {
                rlock.unlock();
            }
        }
    }
    

    3.示例

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    class Count{
        private ReadWriteLock lock = new ReentrantReadWriteLock();
        private Lock rlock = lock.readLock();
        private  Lock wlock = lock.writeLock();
        private int value = 0;
        public void add(int m){
            wlock.lock();
            try{
                value += m;
            }finally {
                wlock.unlock();
            }
        }
        public void dec(int m){
            wlock.lock();
            try{
                value -= m;
            }finally {
                wlock.unlock();
            }
        }
        public int get(){
            rlock.lock();
            try{
                return value;
            }finally {
                rlock.unlock();
            }
        }
    }
    public class Main{
        final static int LOOP = 100;
        public static void main(String[] args) throws Exception{
            Count count = new Count();
            Thread t1 = new Thread(){
                public void run(){
                    for(int i=0;i<LOOP;i++){
                        count.add(1);
                    }
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    for(int i=0;i<LOOP;i++){
                        count.dec(1);
                    }
                }
            };
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(count.get());
        }
    }
    

    ReadWriteLock适用条件:

    • 同一个实例,有大量线程读取,仅有少数线程修改。
    • 例如论坛帖子,回复视为写入,不频繁操作;浏览器看作读取,非常频繁。这种情况下,就可以适用ReadWriteLock

    4. 总结:

    使用ReadWriteLock可以提高读取效率:

    • ReadWriteLock只允许一个线程写入。
    • ReadWriteLock允许多个线程同时读取。
    • ReadWriteLock适合读多写少的场景。
  • 相关阅读:
    面试问题记录-C++
    面试问题记录-网络
    二叉树
    75. Sort Colors 荷兰国旗问题
    桶排序
    数据结构-堆
    快速排序
    第六章 数据库原理
    第五章 Java Web
    第四章 java基础知识
  • 原文地址:https://www.cnblogs.com/csj2018/p/11012137.html
Copyright © 2011-2022 走看看