1.缓存数据的初始化-一次性加载
在程序初始化的过程中调用put()方法,将数据一次性加载进缓存中
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache<K, V> {
final Map<K, V> map = 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 map.get(key);
} finally {
r.unlock();
}
}
//写缓存
V put(K key, V value) {
w.lock();
try {
return map.put(key, value);
} finally {
w.unlock();
}
}
}
2.缓存数据的初始化-按需加载
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache2<K, V> {
final Map<K, V> map = new HashMap<>();
final ReadWriteLock rwl = new ReentrantReadWriteLock();
final Lock r = rwl.readLock();
final Lock w = rwl.writeLock();
V put(K key, V value) {
w.lock();
try {
return map.put(key, value);
} finally {
w.unlock();
}
}
V get(K key) {
V v = null;
r.lock();
try {
v = map.get(key);
} finally {
r.unlock();
}
//缓存中存在,返回
if(v != null) {
return v;
}
//缓存中不存在,查询数据库
w.lock();
try {
//再次验证,其他线程可能已经查询过数据库
v = map.get(key);
if(v == null) {
//查询数据库
System.out.println("数据查询中...");
v = 数据库中的值;
map.put(key, v);
}
return v;
} finally {
w.unlock();
}
}
}
3.锁升级
ReadWriteLock 并不支持这种升级,但是锁的降级却是允许的。以下代码来源自 ReentrantReadWriteLock 的官方示例,略做了改动。
class CachedData {
Object data;
volatile boolean cacheValid;
final ReadWriteLock rwl =
new ReentrantReadWriteLock();
// 读锁
final Lock r = rwl.readLock();
//写锁
final Lock w = rwl.writeLock();
void processCachedData() {
// 获取读锁
r.lock();
if (!cacheValid) {
// 释放读锁,因为不允许读锁的升级
r.unlock();
// 获取写锁
w.lock();
try {
// 再次检查状态
if (!cacheValid) {
data = ...
cacheValid = true;
}
// 释放写锁前,降级为读锁
// 降级是可以的
r.lock(); ①
} finally {
// 释放写锁
w.unlock();
}
}
// 此处仍然持有读锁
try {use(data);}
finally {r.unlock();}
}
}