Bootstrap

并发编程工具集——读写锁-ReadWriteLock(下篇)(十七)

实现缓存的按需加载

  1. 在获取写锁之后,我们并没有直接去查询数据库,而是在代码⑥⑦处,重新验证了一次缓存中是否存在,再次验证如果还是不存在,我们才去查询数据库并更新本地缓存。
  2. 为什么需要再次验证:原因是在高并发的场景下,有可能会有多线程竞争写锁再次验证的方式,能够避免高并发场景下重复查询数据的问题。

读写锁的升级与降级

  1. 锁的升级:先获取读锁,然后升级为写锁
  2. ReadWriteLock 并不支持这种升级
  3. 读锁还没有释放,此时获取写锁,会导致写锁永久等待,最终导致相关线程都被阻塞,永远也没有机会被唤醒。所以锁是不允许升级的
  4. 锁的降级,允许,比如写锁释放前降级为读锁,之后释放写锁,读锁仍然存在且有效

读写锁总结

  1. 读写锁类似于 ReentrantLock,也支持公平模式和非公平模式。
  2. 读锁和写锁都实现了 java.util.concurrent.locks.Lock 接口,所以除了支持 lock() 方法外,tryLock()、lockInterruptibly() 等方法也都是支持的。
  3. 但是有一点需要注意,那就是只有写锁支持条件变量,读锁是不支持条件变量的,读锁调用 newCondition() 会抛出 UnsupportedOperationException 异常。
  4. 实现缓存的案例中并没有考虑到DB数据和缓存数据的一致性
    • 超时机制加载进缓存的数据是有时效的,当缓存数据超时,也就失效了。而访问缓存中失效的数据,会触发缓存重新从源头把数据加载进缓存。
    • 变化时反馈:在源头数据发生变化时,快速反馈给缓存;例如 MySQL 作为数据源,可以通过近实时地解析 binlog 来识别数据是否发生了变化,如果发生了变化就将最新的数据推送给缓存。
    • 数据库和缓存的双写方案:保证数据一致性 Redis 延时双删策略。
;