读写锁
对共享资源进行读和写操作,且写的操作没有那么的频繁。在没有进行写的操作的时候,多个线程同时读取一个资源没有任何问题,所以可以同时允许多个线程读取共享资源。但是一个线程在进行写操作时,就不允许其他线程再对该资源进行读和写的操作了。
针对这种场景,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套哦~