读写锁
对共享资源进行读和写操作,且写的操作没有那么的频繁。在没有进行写的操作的时候,多个线程同时读取一个资源没有任何问题,所以可以同时允许多个线程读取共享资源。但是一个线程在进行写操作时,就不允许其他线程再对该资源进行读和写的操作了。
针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁(独占锁),描述如下:
- 线程进入读锁的前提条件
没有其他线程的写锁,
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。 - 线程进入写锁的前提条件
没有其他线程的读锁
没有其他线程的写锁
读写锁有以下三个重要的特性
(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+"成功"); } }
测试结果:
可以看到,我们在写入1的时候,还未写入一个完整的添加事件,便有一个写入4的线程插入。
使用读写锁后,线程之间就不会插队,一个线程必须等待其他线程完成才能执行。
ReadWriteLock编码模型:
1、创建读写锁
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
可使用两种锁,写锁和读锁
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();//写解锁 } }
执行结果:
源码解读:
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套哦~