JUC之ReadWriteLock(读写锁)

344 阅读1分钟

多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。 但是,如果有一个线程想去共享资源类,就不应该再有其他线程可以对该资源进行读或写。

Java并发包中ReadWriteLock是一个接口,主要有两个方法,如下

实现类ReentrantLock在并发情况下只允许单个线程执行受保护的代码,而在大部分应用中都是读多写少,所以,如果使用ReentrantLock实现这种对共享数据的并发访问控制,将严重影响整体的性能。

  • 读取锁(ReadLock)可以实现并发访问下的多读

  • 写入锁(WriteLock)可以实现每次只允许一个写操作。

但是,在它的实现中,读、写是互斥的,即允许多读,但是不允许读写和写读同时发生。

class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void put(String key,Object value){
        //写锁
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"写入中…………");
            //模拟写入时间300毫秒
            TimeUnit.MICROSECONDS.sleep(300);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入成功!!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //打开写锁
            readWriteLock.writeLock().unlock();
        }
    }

    public void get(String key){
        //读锁
        //加了读锁就是共享锁,所有人都可以读,但是写会阻塞,因为在读时可能正在写,此时会报并发修改异常的
        //读锁是共享锁,写锁是排它锁
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取中…………");
            //模拟读取时间300毫秒
            TimeUnit.MICROSECONDS.sleep(300);
            map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取成功!!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //打开写锁
            readWriteLock.readLock().unlock();
        }
    }

}
public class _读写锁 {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        //写入5个线程
        for (int i = 1; i <= 5; i++) {
            int finalI = i;
            new Thread(()->{
                myCache.put(finalI+"",finalI+"");
            },String.valueOf(i)).start();
        }

        //读取5个线程
        for (int i = 1; i <= 5; i++) {
            int finalI = i;
            new Thread(()->{
                myCache.get(finalI+"");
            },String.valueOf(i)).start();
        }
    }
}

使得对写保持了一致性,读保证了可并发读,防止了在写的时候进行了读的操作,所以这就是读写锁的作用。

  • 小总结 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。
    但是,如果有一个线程想去写共享资源来,就不应该再有其他线程可以对改资源进行读或写:
  • 读-读能共存
  • 读-写不能共存
  • 写-写不能共存