前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动态代理+读写锁实现线程安全的HashMap缓存工具类

动态代理+读写锁实现线程安全的HashMap缓存工具类

作者头像
Yuyy
发布2022-09-21 09:43:25
3270
发布2022-09-21 09:43:25
举报
文章被收录于专栏:yuyy.info技术专栏

背景

jdk1.8之前是没有线程安全的集合工具类,例如currentHashMap,那怎样实现高效、线程安全的集合工具类呢? 可以利用读写锁实现线程安全,动态代理帮助集合作为工具类,产生更多的使用场景,例如缓存

代码

1. 创建缓存基类和子类

image-20201115162726050
image-20201115162726050

基类里的读写锁

代码语言:javascript
复制
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();
}

子类里的基本方法

代码语言:javascript
复制
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. 动态代理实现子类的增强

image-20201115163431132
image-20201115163431132

1. 创建代理类

代码语言:javascript
复制
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. 方法拦截器

代码语言:javascript
复制
@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容器

代码语言:javascript
复制
@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. 单元测试

代码语言:javascript
复制
@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));
}
image-20201115164841240
image-20201115164841240
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 代码
    • 1. 创建缓存基类和子类
    • 2. 动态代理实现子类的增强
      • 1. 创建代理类
        • 2. 方法拦截器
        • 3. 验证
          • 1. 将动态代理类注入IOC容器
            • 2. 单元测试
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档