背景
jdk1.8之前是沒有線程安全的集合工具類,例如
currentHashMap
,那怎樣實作高效、線程安全的集合工具類呢?
可以利用讀寫鎖實作線程安全,動态代理幫助集合作為工具類,産生更多的使用場景,例如緩存
代碼
1. 建立緩存基類和子類
基類裡的讀寫鎖
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void readLock() {
try {
readWriteLock.readLock().lock();
} catch (Exception e) {
throw new CacheRuntimeException(e);
}
}
public void releaseRead(){
readWriteLock.readLock().unlock();
}
public void writeLock() {
try {
readWriteLock.writeLock().lock();
} catch (Exception e) {
throw new CacheRuntimeException(e);
}
}
public void releaseWrite(){
readWriteLock.writeLock().unlock();
}
複制
子類裡的基本方法
private HashBiMap<Integer,String> idAndNameBiMap;
public void init() {
idAndNameBiMap= HashBiMap.create();
System.out.println("idAndNameBiMap init");
}
public Integer getIdByName(String name){
System.out.println("getIdByName");
return idAndNameBiMap.inverse().get(name);
}
public String getNameById(Integer id){
System.out.println("getNameById");
return idAndNameBiMap.get(id);
}
public void putIdAndName(Integer id,String name){
System.out.println("putIdAndName");
idAndNameBiMap.put(id, name);
}
複制
2. 動态代理實作子類的增強
1. 建立代理類
public synchronized AbstractCacheImpl getTarget() {
if (targetCrated) {
return target;
}
if (ClassUtils.isAssignable(this.cacheImpl, AbstractCacheImpl.class)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.cacheImpl);
enhancer.setCallback(this);
target = (AbstractCacheImpl) enhancer.create();
target.setCallbackId(getProxyName());
if (MapUtil.isNotEmpty(cacheProperties)) {
BeanUtil.fillBeanWithMap(cacheProperties, target, false);
}
} else {
throw new CacheRuntimeException(
"cacheImpl isn't a subclass of AbstractCacheImpl" + this);
}
initCache();
targetCrated = true;
return target;
}
複制
2. 方法攔截器
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
try {
AbstractCacheImpl cache = (AbstractCacheImpl) o;
Object retFromSuper = null;
if (ignoreMethods.contains(method.getName())) {
retFromSuper = methodProxy.invokeSuper(cache, objects);
} else if (writeMethod.contains(method.getName())) {
System.out.println("writeLock:"+method.getName());
cache.writeLock();
try {
retFromSuper = methodProxy.invokeSuper(cache, objects);
} finally {
cache.releaseWrite();
System.out.println("releaseWrite");
}
} else if (readMethod.contains(method.getName())) {
System.out.println("readLock:"+method.getName());
cache.readLock();
try {
retFromSuper = methodProxy.invokeSuper(cache, objects);
} finally {
cache.releaseRead();
System.out.println("releaseRead");
}
} else {
retFromSuper = methodProxy.invokeSuper(cache, objects);
}
return retFromSuper;
} catch (Exception e) {
throw new RuntimeException(e).fillInStackTrace();
}
}
複制
3. 驗證
1. 将動态代理類注入IOC容器
@Configuration
public class UserCacheConfigration {
@Bean("userCacheBean")
public CacheProxy userCacheBean() {
return CacheProxy.builder()
.proxyName("userCache")
// 緩存子類的初始化方法
.initMethod("init")
// 緩存子類
.cacheImpl(UserCache.class)
// 需要上讀鎖的方法
.readMethod(Sets.newHashSet("getNameById"))
// 需要上寫鎖的方法
.writeMethod(Sets.newHashSet("putIdAndName"))
.build();
}
}
複制
2. 單元測試
@Test
public void testUserCache(){
UserCache target = (UserCache) cacheProxy.getTarget();
target.putIdAndName(1,"張三");
target.putIdAndName(2,"李四");
System.out.println(target.getIdByName("張三"));
System.out.println(target.getNameById(2));
}
複制