ReadWriteLock可重入读写锁读写锁

简介: ReadWriteLock可重入读写锁读写锁

ReadWriteLock可重入读写锁读写锁

什么是ReadWriteLock读写锁?

它是一个接口,只有一个实现类:ReentrantReadWriteLock(可重复的读写锁,也叫可重入锁)

ReadWriteLock维护一对关联的lock,一个用于只读操作,一个用于写入操作

读的时候可以多个线程同时读,写的时候只能被一个线程写

读锁又叫共享锁 一次性只能被一个线程占用 相当于一个原子性操作

写锁又叫独占锁 多个线程可以同时占有

代码测试,自定义缓存,首先是没有加锁的情况下


package com.wyh.ReadWriteLockTest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * @program: JUC
 * @description: 读写锁测试
 * @author: 魏一鹤
 * @createDate: 2022-02-19 21:56
 **/
//ReadWriteLock是一个接口,只有一个实现类:ReentrantReadWriteLock(可重复的读写锁,也叫可重入锁)
//ReadWriteLock维护一对关联的lock 一个用于只读操作,一个用于写入操作,读的时候可以多个线程同时读,写的时候只能被一个线程写
//自定义缓存
public class ReadWriterLockDemo {
public static void main(String[] args){
//创建静态资源类
        MyCache myCache = new MyCache();
    //循环创建多线程 这几个线程只做读取的操作
        for (int i = 1; i <= 5; i++) {
 //在lambda表达式中无法直接使用循环变量i 需要定义常量指明变量i做一个中间转换
            //然后操作这个常量
            final  int temp=i;
new Thread(()->{
                myCache.put(temp+"",temp+"");
            }).start();
        }
             //循环创建多线程 这几个线程只做存储缓存的操作
             for (int i = 1; i <= 5; i++) {
                 //在lambda表达式中无法直接使用循环变量i 需要定义常量指明变量i做一个中间转换
                 //然后操作这个常量
                 final  int temp=i;
new Thread(()->{
                     myCache.get(temp+"");
                 }).start();
             }
    }
}
//没加锁
class MyCache{
//缓存中一般都是键值对 通过get set 或者put来存或者取
    //volatile保证原子性
    private volatile Map<String,Object> map=new HashMap<>();
    //存缓存 实际是一个写的过程
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入了"+key);
//键值对存缓存
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+"写入"+key+"完毕");
    }
   //取缓存 实际是一个读的过程
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
//通过键取值
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取"+key+"完毕");
    }
}


Thread-0写入了1

Thread-4写入了5

Thread-4写入5完毕

Thread-3写入了4

Thread-1写入了2

Thread-2写入了3

Thread-2写入3完毕

Thread-1写入2完毕

Thread-3写入4完毕

Thread-0写入1完毕

Thread-5读取1

Thread-6读取2

Thread-5读取1完毕

Thread-7读取3

Thread-6读取2完毕

Thread-8读取4

Thread-8读取4完毕

Thread-7读取3完毕

Thread-9读取5

Thread-9读取5完毕


会发现数据比较混乱,没有出现我们想要的情况,一个线程插入的时候被其他线程插队了

然后是加锁后的代码 通过ReentrantReadWriteLock更加细粒度的控制,清楚的指明是读锁还是写锁


package com.wyh.ReadWriteLockTest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * @program: JUC
 * @description: 读写锁测试
 * @author: 魏一鹤
 * @createDate: 2022-02-19 21:56
 **/
// 它主要有以下三个情况
//      1. 读取和读取 可以共存的
//      2. 写入和读取 不可以共存的
//      3. 写入和写入 不可以共存的 写的时候一次性只能进入一个线程,只有执行完毕才会释放锁
//ReadWriteLock是一个接口,只有一个实现类:ReentrantReadWriteLock(可重复的读写锁,也叫可重入锁)
//ReadWriteLock维护一对关联的lock 一个用于只读操作,一个用于写入操作,读的时候可以多个线程同时读,写的时候只能被一个线程写
//自定义缓存
public class ReadWriterLockDemo {
public static void main(String[] args){
//创建ReadWriteLock读写锁接口的实现类 可重入读写锁
        ReentrantReadWriteLock readLock = new ReentrantReadWriteLock();
//创建静态资源类
        MyCacheLock myCache = new MyCacheLock();
 //循环创建多线程 这几个线程只做读取的操作
         for (int i = 1; i <= 5; i++) {
  //在lambda表达式中无法直接使用循环变量i 需要定义常量指明变量i做一个中间转换
            //然后操作这个常量
            final  int temp=i;
new Thread(()->{
                myCache.put(temp+"",temp+"");
            }).start();
          }
//循环创建多线程 这几个线程只做存储缓存的操作
             for (int i = 1; i <= 5; i++) {
                 //在lambda表达式中无法直接使用循环变量i 需要定义常量指明变量i做一个中间转换
                 //然后操作这个常量
                 final  int temp=i;
new Thread(()->{
                     myCache.get(temp+"");
                 }).start();
             }
    }
}
//没加锁
class MyCache{
//缓存中一般都是键值对 通过get set 或者put来存或者取
    //volatile保证原子性
    private volatile Map<String,Object> map=new HashMap<>();
//存缓存 实际是一个写的过程
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入了"+key);
//键值对存缓存
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+"写入"+key+"完毕");
    }
//取缓存 实际是一个读的过程
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
//通过键取值
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取"+key+"完毕");
    }
}
//加锁
//读锁又叫共享锁 一次性只能被一个线程占用 相当于一个原子性操作
//写锁又叫独占锁 多个线程可以同时占有
class MyCacheLock{
//缓存中一般都是键值对 通过get set 或者put来存或者取
    //volatile保证原子性
    private volatile Map<String,Object> map=new HashMap<>();
    //创建  读写锁(可重入锁)
    //它更加细粒度的控制
    //相比于Lock 只能通过lock方法加锁 不能区分读锁还是写锁 但是ReentrantReadWriteLock可以清楚的区分加的是读锁还是写锁
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
  //存缓存 实际是一个写的过程 写入的时候 只想同时被一个线程进行写入操作 是一个原子性操作
    public void put(String key,Object value){
        //ReentrantReadWriteLock的用法和Lock差不多 都要通过try catch finally,try中加锁并且写入业务代码 finally中解锁
        try {
 //加一个写锁 并且加锁 = Lock lock=new Lock() lock.lock();
            reentrantReadWriteLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"写入了"+key);
//键值对存缓存
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入"+key+"完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
   //解锁 =lock.unLock();
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
    //取缓存 实际是一个读的过程 读取的时候 想同时多个线程进行读取操作  所有线程都可以进行读取操作
    public void get(String key){
        //ReentrantReadWriteLock的用法和Lock差不多 都要通过try catch finally,try中加锁并且写入业务代码 finally中解锁
        try {
            //加一个读锁 并且加锁 = Lock lock=new Lock() lock.lock();
            reentrantReadWriteLock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"读取"+key);
//通过键取值
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取"+key+"完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//解锁 =lock.unLock();
            reentrantReadWriteLock.readLock().unlock();
        }
    }
}


Thread-0写入了1

Thread-0写入1完毕

Thread-1写入了2

Thread-1写入2完毕

Thread-2写入了3

Thread-2写入3完毕

Thread-3写入了4

Thread-3写入4完毕

Thread-4写入了5

Thread-4写入5完毕

Thread-7读取3

Thread-7读取3完毕

Thread-8读取4

Thread-8读取4完毕

Thread-9读取5

Thread-9读取5完毕

Thread-6读取2

Thread-6读取2完毕

Thread-5读取1

Thread-5读取1完毕


通过使用可重入读写锁发现,结果是我们想要的,读写分明,写的时候是原子性操作,不会被别的线程干涉

总结

使用其他主要是进行创建 然后使用它的读锁加锁/解锁,和写锁加锁/解锁,和Lock用法差不多,也是通过try catch finlly进行的,try中主要指名是什么锁(WriteLock/ReadLock)加锁(Lock)并且写入业务代码,finally中主要进行解锁,由于是手动的,不解锁(unLock)可能会造成死锁,主要代码如下所示


//创建  读写锁(可重入锁)
//它更加细粒度的控制
//相比于Lock 只能通过lock方法加锁 不能区分读锁还是写锁 但是ReentrantReadWriteLock可以清楚的区分加的是读锁还是写锁
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
//加一个写锁 并且加锁 = Lock lock=new Lock() lock.lock();
reentrantReadWriteLock.writeLock().lock(); 
//解锁 =lock.unLock();
reentrantReadWriteLock.writeLock().unlock();
//加一个读锁 并且加锁 = Lock lock=new Lock() lock.lock();
reentrantReadWriteLock.readLock().lock();
//解锁 =lock.unLock();
reentrantReadWriteLock.readLock().unlock();


它主要有以下三个情况

  1. 读取和读取 可以共存的
  2. 写入和读取 不可以共存的
  3. 写入和写入 不可以共存的 写的时候一次性只能进入一个线程,只有执行完毕才会释放锁
目录
相关文章
ReentrantReadWriteLock读写锁
ReentrantReadWriteLock读写锁
|
7月前
|
缓存 测试技术
ReentrantReadWriteLock 读写锁
ReentrantReadWriteLock 读写锁
46 0
|
4月前
|
Java
JUC(11)各种锁的理解(公平锁、可重入锁、自旋锁、死锁)
这篇文章介绍了Java并发包中的各种锁机制,包括公平锁与非公平锁、可重入锁、自旋锁以及死锁的概念、实现和示例,以及如何使用jps和jstack工具来检测和诊断死锁问题。
|
7月前
|
安全 Java 测试技术
ReentrantReadWriteLock(可重入读写锁)源码解读与使用
ReentrantReadWriteLock(可重入读写锁)源码解读与使用
|
7月前
|
监控
多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解
多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解
124 0
|
Java
【Java并发】ReadWriteLock读写锁的使用
【Java并发】ReadWriteLock读写锁的使用
135 0
【Java并发】ReadWriteLock读写锁的使用
|
安全 Java 测试技术
读写锁还不会用StampedLock就Out了
读写锁还不会用StampedLock就Out了
144 0
读写锁还不会用StampedLock就Out了
|
缓存 Oracle 关系型数据库
可重入读写锁ReentrantReadWriteLock的使用详解
ReentrantReadWriteLock是一把可重入读写锁,这篇文章主要是从使用的角度帮你理解,希望对你有帮助。
226 0
可重入读写锁ReentrantReadWriteLock的使用详解
|
uml
除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
在了解完 ReentrantLock 和 ReentrantReadWriteLock 之后,惊奇的发现 JUC 下还有一个 StampedLock 。 查阅资料发现是 JDK8 新增的一个锁。现在已经 JDK15 了,原谅我的孤陋寡闻,实在是业务开发中用的太少。那行吧,赶紧来看一下 StampedLock 到底是什么?为什么有了 ReentrantLock 和 ReentrantReadWriteLock 之后还要设计一个 StampedLock ?
127 0
|
缓存 Java Android开发
ReentrantReadWriteLock读写锁及其在 RxCache 中的使用
ReentrantReadWriteLock读写锁及其在 RxCache 中的使用
161 0