ReentrantReadWriteLock读写锁实现缓存

262 阅读1分钟
class Cache<K, V> {

    final Map<K, V> m = new HashMap<>();

    final ReadWriteLock rwl = new ReentrantReadWriteLock();
    // 读锁
    final Lock r = rwl.readLock();
    // 写锁
    final Lock w = rwl.writeLock();

    // 读缓存
    V get(K key) {
        r.lock();
        try {
            return m.get(key);
        } finally {
            r.unlock();
        }
    }

    // 写缓存
    V put(K key, V value) {
        w.lock();
        try {
            return m.put(key, value);
        } finally {
            w.unlock();
        }
    }

按需缓存

    //按需缓存
    V getIfNeed(K key) {
        V v = null;
        // 读缓存
        r.lock();
        try {
            v = m.get(key);
        } finally {
            r.unlock();
        }
        // 缓存中存在,返回
        if (v != null) {
            return v;
        }
        // 缓存中不存在,查询数据库
        w.lock();
        try {
            // 再次验证
            // 其他线程可能已经查询过数据库
            v = m.get(key);
            if (v == null) {
                // 查询数据库
                v = getFromSQL();
                m.put(key, v);
            }
        } finally {
            w.unlock();
        }
        return v;
    }

锁升级

    //锁升级的情况
    private void lockUpgrade(K key, V v) {
        // 读缓存
        r.lock();
        try {
            v = m.get(key);
            if (v == null) {
                //此时读锁没有释放,写锁获取会一直阻塞,即不允许锁升级
                w.lock();
                try {
                    // 再次验证并更新缓存
                    // 省略详细代码
                } finally {
                    w.unlock();
                }
            }
        } finally {
            r.unlock();
        }
    } 
   
    //锁降级的情况
    private void lockDegrade(K key) {
        w.lock();
        try {
            // 再次检查状态
            if (!cacheValid()) {
                V data = getFromSQL();
                m.put(key, data);
            }
            // 释放写锁前,降级为读锁
            // 降级是可以的
            r.lock();
        } finally {
            // 释放写锁
            w.unlock();
        }
        try {
            // 此处仍然持有读锁
            m.get(key);
        } finally {
            r.unlock();
        }
    }

    private boolean cacheValid() {
        return false;
    }

    private V getFromSQL() {
        return null;
    }
}