动态代理+读写锁实现线程安全的HashMap缓存工具类
本文最后更新于 798 天前,其中的信息可能已经有所发展或是发生改变。

背景

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

代码

1. 创建缓存基类和子类

image-20201115162726050

  • 基类里的读写锁

    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. 动态代理实现子类的增强

    image-20201115163431132

    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));
    }

    image-20201115164841240

作者:Yuyy
博客:https://yuyy.info

评论

  1. w。
    Windows Chrome
    3年前
    2020-11-16 12:31:03

    java1.6 惨?

    • admin
      博主
      w。
      Linux Chrome
      3年前
      2020-11-16 18:14:19

      这是重点吗!!!

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇