ReadWriterLock(读写锁)
日常记录
1.6文档解释:
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
所有 ReadWriteLock 实现都必须保证 writeLock 操作的内存同步效果也要保持与相关 readLock 的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。
尽管读-写锁的基本操作是直截了当的,但实现仍然必须作出许多决策,这些决策可能会影响给定应用程序中读-写锁的效果。这些策略的例子包括:
- 在 writer 释放写入锁时,reader 和 writer 都处于等待状态,在这时要确定是授予读取锁还是授予写入锁。
Writer优先比较普遍,因为预期写入所需的时间较短并且不那么频繁。Reader优先不太普遍,因为如果 reader
正如预期的那样频繁和持久,那么它将导致对于写入操作来说较长的时延。公平或者“按次序”实现也是有可能的。 - 在 reader 处于活动状态而 writer 处于等待状态时,确定是否向请求读取锁的 reader 授予读取锁。Reader 优先会无限期地延迟 writer,而writer 优先会减少可能的并发。
- 确定是否重新进入锁:可以使用带有写入锁的线程重新获取它吗?可以在保持写入锁的同时获取读取锁吗?可以重新进入写入锁本身吗?
- 可以将写入锁在不允许其他 writer 干涉的情况下降级为读取锁吗?可以优先于其他等待的 reader 或 writer
将读取锁升级为写入锁吗?
方法
- Lock readLock()
返回用于读取操作的锁。 - Lock writeLock()
返回用于写入操作的锁。
优缺点
优点:
防止,在多线程下,读写顺序混乱
缺点:
写数据时,一次,只允许一个线程写,但是允许多个线程读。
读数据时,允许多个线程读,但是不允许线程写数据,只有读取完了,才能写数据
缺点原因:出现写锁的降级,为读锁(写锁可以降级,读锁读锁不可以)
写锁降级顺序:
获取写锁----》获取读锁----》释放写锁-----》释放读锁
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 读取锁:ReaderWriterLock
* 文档:
* ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。
* 只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
* 所有 ReadWriteLock 实现都必须保证 writeLock 操作的内存同步效果也要保持与相关 readLock 的联系。
* 也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。
* 解释:防止,在多线程下,读写顺序混乱
* 缺点:
* 写数据时,一次,只允许一个线程写,但是允许多个线程读。
* 读数据时,允许多个线程读,但是不允许线程写数据,只有读取完了,才能写数据
* 原因:出现写锁的降级,为读锁(写锁可以降级,读锁读锁不可以)
* 写锁降级顺序:
* 获取写锁----》获取读锁----》释放写锁-----》释放读锁
*
*/
public class ReentrantReadWriterLockUse {
//模拟缓存
private static volatile HashMap mp= new HashMap<String,Object>();
//读写锁可重入锁,解决多线程情况下,读写顺序情况
private static ReadWriteLock rwLock=new ReentrantReadWriteLock();
/**
* 写方法
* @param key
* @param value
*/
public static void writer(String key,Object value){
rwLock.writeLock().lock();
//添加写锁
try {
//每个写入线程,睡眠0.5秒
TimeUnit.MILLISECONDS.sleep(10);
mp.put(key,value);
System.out.println("正在写入:第"+key+"个值:"+value);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放写锁
rwLock.writeLock().unlock();
}
}
/**
* 读方法
* @param key
* @return
*/
public static Object read(String key){
try {
//添加读锁
rwLock.readLock().lock();
//每个写入线程,睡眠0.5秒
TimeUnit.MILLISECONDS.sleep(10);
Object result = mp.get(String.valueOf(key));
System.out.println("------正在读取:第"+result+"个值:"+result.toString());
return result;
} catch (InterruptedException e) {
e.printStackTrace();
return "读取失败";
}finally {
//释放读锁
rwLock.readLock().unlock();
}
}
public static void main(String[] args) {
for (int i = 1; i <=5 ; i++) {
final int num=i;
new Thread(()->{
writer("key"+num,num);
System.out.println("数据--写入完成:"+" key:"+num+" value:"+num);
}).start();
}
for (int i = 1; i <=5 ; i++) {
final int num=i;
new Thread(()->{
Object read =read("key" + num);
System.out.println("数据--读取完成:"+read.toString());
}).start();
}
}
}