ReadWriteLock也是一个接口,提供了readLock和writeLock两种锁的操作机制,一个资源可以被多个线程同时读,但是只能被一个线程写
,但是不能同时存在读和写线程。
读写锁机制
- 读—读 不互斥
- 读—写 互斥
- 写—写 互斥
演示代码:
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache cache = new MyCache();
//多线程写入
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
cache.put(temp+"",temp+";");
}).start();
}
//多线程读取
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
cache.get(temp+"");
}).start();
}
}
}
/**
* 创建一个缓存类,未加锁的情况
*/
class MyCache{
private volatile Map<String,Object> map = new HashMap<>();
public void put(String k,Object v){
System.out.println(Thread.currentThread().getName()+"进行写入");
map.put(k,v);
System.out.println(Thread.currentThread().getName()+"写入完成");
}
public void get(String k){
System.out.println(Thread.currentThread().getName()+"进行读取");
map.get(k);
System.out.println(Thread.currentThread().getName()+"读取完成");
}
}
运行结果
可以看到,在线程1进行写入的这段时间内,线程2和线程3也进行了写入,这就造成了写入时互斥的问题。当进行写入操作的时候,只有一条线程能进行写入,其他线程只能等候。
因此,我们需要对缓存进行优化,加锁来控制
代码实现
class MyCacheLock{
private volatile Map<String,Object> map = new HashMap<>();
//更加细粒度的操作:当进行写入的时候,只能有一个线程去写入;而读取的时候可以有多个线程读取
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String k,Object v){
//写入时加锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"进行写入");
map.put(k,v);
System.out.println(Thread.currentThread().getName()+"写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
readWriteLock.writeLock().unlock();
}
}
public void get(String k){
//读取时加锁,(为了防止读写共存,当多个同时读取时被允许读取)
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"进行读取");
map.get(k);
System.out.println(Thread.currentThread().getName()+"读取完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
readWriteLock.readLock().lock();
}
}
}
运行结果
可以看到,加锁后再进行写入操作时,就不存在同时写入的问题;当写锁被获取后,其他线程对于读锁和写锁的获取均被阻塞,而只有写锁被释放之后,其他读写操作才能继续。