9、读写锁:ReadWriteLock
读写分离:读写分离是一种思想。
之前讲的Lock是一个同步锁,它对资源的读和写,要么都锁住,要么都不锁,有的时候我们的资源,希望读的时候不锁,写的时候锁住,这样在安全的基础上能提高很大的效率。
我们希望锁只添加在需要的地方,如在写的时候,加锁,只允许一个线程去操作,读的时候不加锁,所有的线程都可以去读。
这样ReadWriteLock运营而生。
读锁(共享锁): 这个锁可以被多个线程持有!
写锁(独占锁):这个锁一次只能被一个线程占用!
不使用锁的情况下,示例代码如下:
package com.interview.concurrent.readwritelock;
import java.util.HashMap;
import java.util.Map;
/**
* @author DDKK.COM 弟弟快看,程序员编程资料站
* @description 描述
* @date 2023/2/23 15:54
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
//不加锁
ResourcePool resourcePool = new ResourcePool();
//开启5个线程去写
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(() - resourcePool.put(temp,temp),"写线程" + i).start();
}
//开启5个线程去读
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(() - resourcePool.get(temp),"读线程" + i).start();
}
}
}
/**
* @description: 资源池,,没有加锁,资源池使用volatile,保证可见性
* @author DDKK.COM 弟弟快看,程序员编程资料站
* @date 2023/2/23 16:07
*/
class ResourcePool{
private volatile Map<Object,Object map = new HashMap<Object,Object();
public void put(Object key,Object value){
System.out.println(Thread.currentThread().getName() + ":写入数据" + key);
map.put(key,value);
System.out.println(Thread.currentThread().getName() + ":写入数据完成" + value);
}
public void get(Object key){
System.out.println(Thread.currentThread().getName() + ":获取数据" + key);
Object object = map.get(key);
System.out.println(Thread.currentThread().getName() + ":获取数据完成" + object);
}
}
使用读写锁后,线程之间就不会插队,一个线程必须等待其他线程完成才能执行。
ReadWriteLock编码模型:
1、创建读写锁
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
可使用两种锁,写锁和读锁
2.1、加写锁
readWriteLock.writeLock().lock();
2.2、业务代码:…
2.3、解写锁
try/catch/finally {
readWriteLock.writeLock().unlock();
}
readWriteLock.readLock().lock();
3.1、加锁
readWriteLock.readLock().lock();
3.1、加锁
3.2、业务代码:…
3.3、解读锁
try/catch/finally {
readWriteLock.readLock().unlock();
}
示例代码如下:
/**
* @description: 资源池,,没有加锁,资源池使用volatile,保证可见性
* @author DDKK.COM 弟弟快看,程序员编程资料站
* @date 2023/2/23 16:07
*/
class ResourcePoolReadWriteLock{
private volatile Map<Object,Object map = new HashMap<Object,Object();
//1、创建读写锁
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(Object key,Object value){
//2、加锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ":写入数据" + key);
map.put(key,value);
System.out.println(Thread.currentThread().getName() + ":写入数据完成" + value);
} catch (Exception e) {
e.printStackTrace();
} finally {
//3、解锁
readWriteLock.writeLock().unlock();
}
}
public void get(Object key){
//2、加锁
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ":获取数据" + key);
Object object = map.get(key);
System.out.println(Thread.currentThread().getName() + ":获取数据完成" + object);
} catch (Exception e) {
e.printStackTrace();
} finally {
//3、解锁
readWriteLock.readLock().unlock();
}
}
}
注:
1、线程是CPU调度的,与执行顺序无关;
2、ReadWriteLock的唯一实现类是ReentrantReadWriteLock
3、Lock不能区分读和写;
4、读写分离,提高效率~ 判断业务中那些代码是只读的业务,不要去锁这些业务。