如何优化读多写少的场景
读写锁原则
允许多个线程同时读共享变量; 只允许一个线程写共享变量; 如果一个写线程正在执行写操作,此时禁止读线程读共享变量。
不支持从读锁到写锁的升级,反之支持。
锁升级测试
结论
支持写锁重入: 写锁后再加写锁,可以运行结束 支持读锁重入:读锁后再加读锁,可以运行结束 支持降级:先加写锁 再加读锁可以运行结束(🤔🤔🤔)
不支持升级:先加读锁 再加写锁可以运行结束(🤔🤔🤔)
public static void main(String[] args) {
PaymentServiceImpl p = new PaymentServiceImpl();
p.test();
}
public void test(){
r.lock();
try{
System.out.println("进入读锁");
w.lock();
try{
Thread.sleep(1000);
System.out.println("进入写锁");
}finally {
w.lock();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
r.unlock();
}
System.out.println("执行完毕");
}
课后思考
有同学反映线上系统停止响应了,CPU 利用率很低,你怀疑有同学一不小心写出了读锁升级写锁的方案,那你该如何验证自己的怀疑呢?
答案
后记
java 中的读写锁类似mysql中的lock in share mode (select from test where id = 1 lock in share mode;)
for update 是读读互斥,读写互斥(select from test where id = 1 for update)