1、BlockingCache 是在原有 Cache 实现之上添加了阻塞线程的特性,采用
ConcurrentHashMap<Object, CountDownLatch> 和CountDownLatch来实现加锁解锁
public Object getObject(Object key) {
acquireLock(key);
Object value = delegate.getObject(key);
if (value != null) {
releaseLock(key);
}
return value;
}
private void acquireLock(Object key) {
CountDownLatch newLatch = new CountDownLatch(1);
while (true) {
CountDownLatch latch = locks.putIfAbsent(key, newLatch);
if (latch == null) {
break;
}
try {
if (timeout > 0) {
boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS);
if (!acquired) {
throw new CacheException(
"Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId());
}
} else {
latch.await();
}
} catch (InterruptedException e) {
throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
}
}
}
private void releaseLock(Object key) {
CountDownLatch latch = locks.remove(key);
if (latch == null) {
throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen.");
}
latch.countDown();
}
2.FifoCache 装饰器,它是 FIFO(先入先出)策略的装饰器。在系统运行过程中,我们会不断向 Cache 中增加缓存条目,当 Cache 中的缓存条目达到上限的时候,则会将 Cache 中最早写入的缓存条目清理掉,这也就是先入先出的基本原理。
private final Cache delegate;
private final Deque<Object> keyList;
private int size;
public FifoCache(Cache delegate) {
this.delegate = delegate;
this.keyList = new LinkedList<>();
this.size = 1024;
}
@Override
public void putObject(Object key, Object value) {
cycleKeyList(key);
delegate.putObject(key, value);
}
private void cycleKeyList(Object key) {
//尾部添加
keyList.addLast(key);
if (keyList.size() > size) {
// 头部删除
Object oldestKey = keyList.removeFirst();
delegate.removeObject(oldestKey);
}
}
3.MyBatis 还支持 LRU(Least Recently Used,近期最少使用算法)策略来清理缓存。LruCache 就是使用 LRU 策略清理缓存的装饰器实现,如果 LruCache 发现缓存需要清理,它会清除最近最少使用的缓存条目。
public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024);
}
public void setSize(final int size) {
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L;
// 通过LinkedHashMap来的removeEldestEntry方法,将map中元素的个数大于1024的时,将清除最近最少使用的缓存条目
@Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);
}
private void cycleKeyList(Object key) {
keyMap.put(key, key);
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
4.SoftCache
当 JVM 内存不足时,GC 才会回收那些只被软引用指向的对象,从而避免 OutOfMemoryError。当 GC 将只被软引用指向的对象全部回收之后,内存依然不足时,JVM 才会抛出 OutOfMemoryError。根据软引用的这一特性,我们会发现软引用特别适合做缓存,因为缓存中的数据可以从数据库中恢复,所以即使因为 JVM 内存不足而被回收掉,也可以通过数据库恢复缓存中的对象。
5.WeakCache
只被弱引用指向的对象只在两次 GC 之间存活。而只被软引用指向的对象是在 JVM 内存紧张的时候才被回收,它是可以经历多次 GC 的,这就是两者最大的区别。在 WeakReference 指向的对象被回收时,也会将 WeakReference 对象添加到关联的队列中
6.LoggingCache
添加计算请求缓存命中率,并添加日志
7.SerializedCache
对缓存数据进行序列化和反序列化操作
8.SynchronizedCache
每个方法上都加了synchronized
9.ScheduledCache
10.TransactionalCache