JUC并发编程学习(九)-读写锁

简介: JUC并发编程学习(九)-读写锁

读写锁


对共享资源进行读和写操作,且写的操作没有那么的频繁。在没有进行写的操作的时候,多个线程同时读取一个资源没有任何问题,所以可以同时允许多个线程读取共享资源。但是一个线程在进行写操作时,就不允许其他线程再对该资源进行读和写的操作了。

针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁(独占锁),描述如下:

20200401134307494.png

  • 线程进入读锁的前提条件
    没有其他线程的写锁,
    没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。
  • 线程进入写锁的前提条件
    没有其他线程的读锁
    没有其他线程的写锁

读写锁有以下三个重要的特性

(1)公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。


(2)重进入:读锁和写锁都支持线程重进入。


(3)锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁。


案例分析:

我们使用hashmap来进行读写操作,在未使用锁的情况,示例代码如下

package com.jp.readwriterlockDemo;
import java.util.HashMap;
import java.util.Map;
/**
* @className:
* @PackageName: com.jp.readwriterlockDemo
* @author: youjp
* @create: 2020-05-17 22:12
* @description:    TODO  读写锁demo
* @Version: 1.0
*/
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        //先写入
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                //写入
                myThread.wirte(String.valueOf(temp),temp);
            },String.valueOf(i)).start();
        }
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                //读取
                myThread.read(String.valueOf(temp));
            },String.valueOf(i)).start();
        }
    }
}
//线程操作资源类
class MyThread{
    private volatile HashMap<String,Object> map=new HashMap<>();
    //读方法
    void read(String key){
        System.out.println("线程"+Thread.currentThread().getName()+"  key:"+key+"读取到"+map.get(key));
    }
    //写方法
    void wirte(String key,Object value){
        System.out.println("线程"+Thread.currentThread().getName()+" 开始写入key:"+key);
        map.put(key,value);
        System.out.println("线程"+Thread.currentThread().getName()+"写入key:"+key+" value:"+value+"成功");
    }
}

测试结果:

20200401134307494.png

可以看到,我们在写入1的时候,还未写入一个完整的添加事件,便有一个写入4的线程插入。

使用读写锁后,线程之间就不会插队,一个线程必须等待其他线程完成才能执行。

ReadWriteLock编码模型:

1、创建读写锁

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

可使用两种锁,写锁和读锁

20200401134307494.png

2.加锁

lock.readLock().lock(); //读加锁
lock.writeLock().lock(); //写加锁

3.解锁

//相应的读锁或写锁调用解锁方法
lock.readLock().unlock();//读解锁
lock.writeLock().unlock();//写解锁

示例代码如下:

package com.jp.readwriterlockDemo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * @className:
 * @PackageName: com.jp.readwriterlockDemo
 * @author: youjp
 * @create: 2020-05-17 22:12
 * @description:    TODO  读写锁demo
 * @Version: 1.0
 */
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        //先写入
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                //写入
                myThread.wirte(String.valueOf(temp),temp);
            },String.valueOf(i)).start();
        }
        for (int i = 1; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                //读取
                myThread.read(String.valueOf(temp));
            },String.valueOf(i)).start();
        }
    }
}
//线程操作资源类
class MyThread{
    private volatile HashMap<String,Object> map=new HashMap<>();
    private ReadWriteLock lock=new ReentrantReadWriteLock();//可重入读写锁
    //读方法
    void read(String key){
        lock.readLock().lock(); //读加锁
        System.out.println("线程"+Thread.currentThread().getName()+"  key:"+key+"读取到"+map.get(key));
        lock.readLock().unlock();//读解锁
    }
    //写方法
    void wirte(String key,Object value){
        lock.writeLock().lock(); //写加锁
        System.out.println("线程"+Thread.currentThread().getName()+" 开始写入key:"+key);
        map.put(key,value);
        System.out.println("线程"+Thread.currentThread().getName()+"写入key:"+key+" value:"+value+"成功");
        lock.writeLock().unlock();//写解锁
    }
}

执行结果:

20200401134307494.png

源码解读:

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
    /** 读锁 */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** 写锁 */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    final Sync sync;
    /** 使用默认(非公平)的排序属性创建一个新的 ReentrantReadWriteLock */
    public ReentrantReadWriteLock() {
        this(false);
    }
    /** 使用给定的公平策略创建一个新的 ReentrantReadWriteLock */
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }
    /** 返回用于写入操作的锁 */
    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    /** 返回用于读取操作的锁 */
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
    abstract static class Sync extends AbstractQueuedSynchronizer {}
    static final class NonfairSync extends Sync {}
    static final class FairSync extends Sync {}
    public static class ReadLock implements Lock, java.io.Serializable {}
    public static class WriteLock implements Lock, java.io.Serializable {}
}

可以看到,ReentrantReadWriteLock实现了ReadWriteLock接口,ReadWriteLock接口定义了获取读锁和写锁的规范,具体需要实现类去实现;同时其还实现了Serializable接口,表示可以进行序列化,在源代码中可以看到ReentrantReadWriteLock实现了自己的序列化逻辑。


参考博文:

https://www.cnblogs.com/xiaoxi/p/9140541.html


有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~


相关文章
|
2月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
5月前
|
存储 缓存 Java
深入剖析Java并发库(JUC)之StampedLock的应用与原理
深入剖析Java并发库(JUC)之StampedLock的应用与原理
深入剖析Java并发库(JUC)之StampedLock的应用与原理
|
6月前
|
安全 Java
多线程(进阶三:JUC)
多线程(进阶三:JUC)
71 0
|
Web App开发 安全 Java
JUC高并发编程(一)——JUC基础知识
JUC高并发编程(一)——JUC基础知识
138 0
|
SpringCloudAlibaba 安全 Java
JUC并发编程(二):线程相关知识点
实现编发编程的主要手段就是多线程。线程是操作系统里的一个概念。接下来先说说两者的定义、联系与区别。
77 0
|
存储 SQL 缓存
JUC 并发编程学习笔记(总)
JUC 并发编程学习笔记(总)
99 0
JUC 并发编程学习笔记(总)
|
安全 Java Linux
JUC (java并发编程学习分享篇)
JUC (java并发编程学习分享篇)
74 0
JUC并发编程学习(一)-什么是JUC
JUC并发编程学习(一)-什么是JUC
JUC并发编程学习(一)-什么是JUC
|
Java 调度 C++
JUC 并发编程学习笔记(上)
JUC 并发编程学习笔记(上)
84 0
JUC 并发编程学习笔记(上)
|
缓存 Java API
JUC 并发编程学习笔记(中)
JUC 并发编程学习笔记(中)
74 0
JUC 并发编程学习笔记(中)