弱引用比软引用的引用强度还要弱。弱引用可以引用一个对象,但无法阻止这个对象被GC回收,也就是说,在JVM进行垃圾回收的时候,若发现某个对象只有一个弱引用指向它,那么这个对象会被GC立刻回收。(即遇GC比死,存活的时间为两次GC之间)
// Entry继承的是WeakReference。 // 其他内容参考弱引用Cache private static class WeakEntry extends WeakReference<Object> { private final Object key; private WeakEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) { super(value, garbageCollectionQueue); this.key = key; } } LoggingCache一个支持打印Debug级别的缓存命中率的MyBatisCache
// 日志打印的log对象 private final Log log; private final Cache delegate; // 请求数 protected int requests = 0; // 缓存命中数 protected int hits = 0; public LoggingCache(Cache delegate) { //通过构造函数,将Cache组合进来,取名”委托“ this.delegate = delegate; //log通过缓存id作为表示 this.log = LogFactory.getLog(getId()); } @Override public void putObject(Object key, Object object) { delegate.putObject(key, object); } @Override public Object getObject(Object key) { requests++; // 请求数增加 final Object value = delegate.getObject(key); if (value != null) { hits++; // 缓存命中,命中数增加 } if (log.isDebugEnabled()) { log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio()); // 打印缓存命中率 } return value; } @Override public Object removeObject(Object key) { return delegate.removeObject(key); } private double getHitRatio() { // 计算缓存命中率 return (double) hits / (double) requests; }LoggingCache使得缓存读取的时候能够有缓存命中率的日志打印,挺实用的增强。
BlockingCache一个支持阻塞的MyBatisCache
private long timeout; private final Cache delegate; //每个key都有自己的ReentrantLock private final ConcurrentHashMap<Object, ReentrantLock> locks; public BlockingCache(Cache delegate) { this.delegate = delegate; this.locks = new ConcurrentHashMap<Object, ReentrantLock>(); } @Override public void putObject(Object key, Object value) { try { delegate.putObject(key, value); // 委托写入缓存 } finally { releaseLock(key); // 释放锁 } } @Override public Object getObject(Object key) { acquireLock(key); // 尝试获取锁 Object value = delegate.getObject(key); if (value != null) { releaseLock(key); // 获取到缓存后 释放锁 } return value; } @Override public Object removeObject(Object key) { // despite of its name, this method is called only to release locks releaseLock(key); // 释放锁 return null; } private void acquireLock(Object key) { Lock lock = getLockForKey(key); // 获取对应的Lock,没有则新增一把Lock if (timeout > 0) { try { boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS); // 尝试超时加锁 if (!acquired) { throw new CacheException("Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); } } catch (InterruptedException e) { throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e); } } else { lock.lock(); // 加锁 } } private ReentrantLock getLockForKey(Object key) { ReentrantLock lock = new ReentrantLock(); ReentrantLock previous = locks.putIfAbsent(key, lock); return previous == null ? lock : previous; } private void releaseLock(Object key) { ReentrantLock lock = locks.get(key); // 获取Key对应的Lock if (lock.isHeldByCurrentThread()) { // 如果是当前线程持有lock,则释放锁 lock.unlock(); } } SynchronizedCache一个支持同步的MyBatisCache,从名称就能知道实现原理是synchronized关键字
public SynchronizedCache(Cache delegate) { this.delegate = delegate; } @Override public synchronized int getSize() { return delegate.getSize(); } @Override public synchronized void putObject(Object key, Object object) { delegate.putObject(key, object); } @Override public synchronized Object getObject(Object key) { return delegate.getObject(key); } @Override public synchronized Object removeObject(Object key) { return delegate.removeObject(key); }同步缓存就是给核心方法加上了同步锁,保证了线程安全。
跟随源码看看解析-装饰过程