@[TOC] 聊聊Mybatis的缓存之装饰者模式 装饰器的Component被装饰者 Cache接口: public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key
@[TOC]
聊聊Mybatis的缓存之装饰者模式
装饰器的Component被装饰者
Cache接口:
public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key); void clear(); int getSize(); default ReadWriteLock getReadWriteLock() { return null; } }PerpetualCache实现了这个接口,使用HashMap来缓存数据
Cache是装饰器模式的Component接口,PerpetualCache是接口的实现类
装饰器模式的装饰者
BlockingCache实现了Cache接口,具有阻塞线程的功能,看一下它的获取缓存数据的方法:
@Override public Object getObject(Object key) { acquireLock(key); Object value = delegate.getObject(key); if (value != null) { releaseLock(key); } return value; }获取锁BlockingCache的acquireLock()方法:
private final ConcurrentHashMap<Object, CountDownLatch> locks; 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); } } }看下releaseLock()方法:
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(); }在真正使用的时候,线程之间产生竞争,线程a发现key没有关联的CountDownLatch对象,获取锁成功,获取锁成功后在ConcurrentHashMap集合中维护key和CountDownLatch对象的关联,线程b进入是没办法获取锁的,产生阻塞,这时候需要查询数据库的数据并调用putObject()方法来释放锁,从而线程b被唤醒
总结
本篇文章主要从装饰者模式的角度分析了一下缓存模块的被装饰器接口Cache和实现类PerpetualCache,PerpetualCache通过HasnMap来缓存数据,还介绍了一个装饰器BlockingCache,分析了它获取缓存的逻辑:先获取key对应的锁然后获取数据最后释放锁,CountDownLatch中保存key和CountDownLatch对象的关联来表示加锁是否成功