如何优化读多写少的场景

读写锁原则

允许多个线程同时读共享变量; 只允许一个线程写共享变量; 如果一个写线程正在执行写操作,此时禁止读线程读共享变量。

不支持从读锁到写锁的升级,反之支持。

锁升级测试
结论

支持写锁重入: 写锁后再加写锁,可以运行结束 支持读锁重入:读锁后再加读锁,可以运行结束 支持降级:先加写锁 再加读锁可以运行结束(🤔🤔🤔)
不支持升级:先加读锁 再加写锁可以运行结束(🤔🤔🤔)

  1. public static void main(String[] args) {
  2. PaymentServiceImpl p = new PaymentServiceImpl();
  3. p.test();
  4. }
  5. public void test(){
  6. r.lock();
  7. try{
  8. System.out.println("进入读锁");
  9. w.lock();
  10. try{
  11. Thread.sleep(1000);
  12. System.out.println("进入写锁");
  13. }finally {
  14. w.lock();
  15. }
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. } finally {
  19. r.unlock();
  20. }
  21. System.out.println("执行完毕");
  22. }

jstack 结果
image.png

课后思考

有同学反映线上系统停止响应了,CPU 利用率很低,你怀疑有同学一不小心写出了读锁升级写锁的方案,那你该如何验证自己的怀疑呢?

答案

jstack查看。

后记

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)