1. Ideas
1. Open the read lock first to get the cached data value
2. Judge the value, if it is empty, close the read lock; open the write lock, and get the cache data value (other threads may assign values), if the value is empty, assign a value to the cache. And downgrade the write lock to a read lock.
3. If it is not empty, get the value and close the read lock.
Note : Whether the key of the read-write lock has a cache value, what operations are performed, and what operations are not performed. This process must consider other thread assignment issues, and then perform the corresponding operations.
Second, the code example
// 读写锁
public static void ReentrantReadWriteLockCacheSystem() {
//这里为了实现简单,将缓存大小设置为4。
Map<String, String> cacheMap = new HashMap<>(4);
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
for (int i = 0; i < 20; i++) { //同时开启20个线程访问缓存
final String key = String.valueOf(i % 4);
log.info(Thread.currentThread().getName()+"key:{}",key);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
//①读取缓存时获取读锁
readWriteLock.readLock().lock();
//获取读锁后通过key获取缓存中的值
String valueStr = cacheMap.get(key);
log.info("value:{}",valueStr);
//缓存值不存在
if (valueStr == null) {
//③释放读锁后再尝试获取写锁
// 读不到数据,就关闭读锁,开启写锁
readWriteLock.readLock().unlock(); //关闭读锁
try {
//④获取写锁来写入不存在的key值,
readWriteLock.writeLock().lock();
valueStr = cacheMap.get(key);
log.info("key:{}"+key+",关闭读锁后value:{}",valueStr);
if (valueStr == null) {
valueStr = key + " --- value";
log.info("为锁赋值:{}",valueStr);
cacheMap.put(key, valueStr); //写入值
System.out.println(Thread.currentThread().getName() + " --------- put " + valueStr);
}
// ⑥锁降级,避免被其他写线程抢占后再次更新值,保证这一次操作的原子性
readWriteLock.readLock().lock();
log.info("读锁操作:{}"+key);
System.out.println(Thread.currentThread().getName() + " --------- get new " + valueStr);
} finally {
log.info("写锁操作:{}",key);
readWriteLock.writeLock().unlock(); //⑤释放写锁
}
} else {
System.out.println(Thread.currentThread().getName() + " ------ get cache value");
}
} finally {
log.info("释放读锁:{}",key);
readWriteLock.readLock().unlock(); //②释放读锁
}
}
}, String.valueOf(i));
thread.start();
}
}
Third, the technology involved
1, lombok, multi-threaded read and write class ReentrantReadWriteLock
2. Project demo. https://github.com/krycai/MultiThread's class LockDemo2