使用读写锁替代完全互斥
的同步锁
, 在写少读多
的场景下可以提高效率(有写
才互斥,全读
可并发)。
对于一个读写锁来说,同一时刻, 如果一个线程拿到了写
锁,排斥其他线程获取锁,不管想要获取读
锁 还是写
锁,都必须等待;
统一时刻,没有线程在写
,都是在读
的情况下, 不排斥 其他线程获取读
锁 并发读取数据, 如果此时有线程想要获取写
锁 的话、需要等到当前所有正在读
的线程执行完成,才能获取到写
锁。
代码示例
import cn.hutool.core.lang.Console;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* juc 读写锁
* 有线程持有 写 锁的时候, 拒绝其他线程获取 读/写 锁
* 有线程持有 读 锁的时候, 不拒绝其他线程获取 读 锁 , 并发访问 , 此时 有线程想要获取 写 锁 , 只能等这批 读 线程 执行 完成
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
// 使用 读写锁的 数据
Data data = new Data();
// 开启100个读线程, 5个写线程
for (int i = 0; i < 105; i++) {
// i 的值为 3/6/9/12/15 时, 创建 写线程
// i 是其他值 创建 读线程
if (i<16 && i%3 == 0) {
new Thread(() -> { data.setValue(10); }, "写线程-"+i).start();
} else {
new Thread(() -> { data.getValue(); }, "读线程-" + i).start();
}
}
}
}
class Data {
private int value = 0;
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
// 读 数据 操作
public int getValue() {
lock.readLock().lock();
try {
Console.log("{} = {}", Thread.currentThread().getName(), value);
}finally {
lock.readLock().unlock();
}
return value;
}
// 写 数据 操作
public void setValue(int value) {
lock.writeLock().lock();
try {
this.value += value;
Console.log("{} = {}", Thread.currentThread().getName(), this.value);
}finally {
lock.writeLock().unlock();
}
}
}