使用缓存对象ConcurrentLruCache之后key值无法命中,导致系统性能无法提升反降

1、问题描述:

采用ConcurrentLruCache 作为JVM缓存池对象

public class UserManager {


    private ConcurrentLruCache<UserCacheKey, UserInfo> cache = new ConcurrentLruCache<UserCacheKey, UserInfo>(100, new Function<UserCacheKey, UserInfo>() {
        @Override
        public UserInfo apply(UserCacheKey key) {
            return loadUserInfo(key.getUserid(), key.getActivity());
        }
    });

    public UserInfo findByPortalId(String userid, String activityname) {
        UserInfo info = null;
        try {
            info = cache.get(generaterCacheKey(userid, activityname));
        } catch (Exception e) {
            GFLogUtil.i(userid + activityname + " is null");
        }
        return info;
    }

    private UserCacheKey generaterCacheKey(String userid, String activityname) {
        return new UserCacheKey(userid, activityname);
    }

}

 从上面的代码段可以看到,缓存的KEY值竟是一个自定义对象类型,如下所示:

public class UserCacheKey {

    private String userid = "";

    private String activity = "";

    public UserCacheKey(String userid, String activity) {
        this.userid = userid;
        this.activity = activity;
    }

    public String getUserid() {
        return userid;
    }

    public String getActivity() {
        return activity;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof UserCacheKey) {
            UserCacheKey key = (UserCacheKey) obj;
            return userid.equals(key.getUserid()) && activity.equals(key.getActivity());
        }
        return false;
    }
}

以上代码展示了缓存KEY值对象内部结构,还是比较简单:

        (1)定义了2个成员变量,用来作为从数据库检索数据的条件参数。

        (2)重写了equals方式,用来把一个对象添加到缓存池中的时候,根据内容判定是否存在相同对象。

2、问题分析:

        通过第1步的操作,表面上看起来没有什么问题,而实际使用中发现缓存KEY值并没有直接命中,每次查询出的对象都是走的DB查询。

         为什么传入对象的属性值即便是相同的,而缓存池对象却每次都以为是新对象呢?带着这个问题,在深入ConcurrentLruCache本身去看就会发现,其内部采用的是ConcurrentHashMap实现存储机制,既然有HashMap的影子,那问题就比较明朗了。因为HashMap存储对象的时候,首先比较的是对象的HashCode值,如果HashCode值相同的情况下,才在调用对象的equals方法比较对象的内容。

        到此为止,我想问题已经知道出在UserCacheKey 本身了,在该类中忽略了一个很重要的方法,就是我们经常听到的一句话:“重写类的equals方式,最好也重写类的hashCode方法”

3、问题解决:

修改之后的UserCacheKey 如下所示:

public class UserCacheKey {

    private String userid = "";

    private String activity = "";

    public UserCacheKey(String userid, String activity) {
        this.userid = userid;
        this.activity = activity;
    }

    public String getUserid() {
        return userid;
    }

    public String getActivity() {
        return activity;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof UserCacheKey) {
            UserCacheKey key = (UserCacheKey) obj;
            return userid.equals(key.getUserid()) && activity.equals(key.getActivity());
        }
        return false;
    }


    @Override
    public int hashCode() {
        return Objects.hash(userid, activity);
    }
}

问题总结:

1、对于一个java对象,其hashCode方法的重要性,它是判定俩对象是否相同的首选判定依据;

2、加深对HashMap存储机制的了解,它先比较俩对象的hashCode,在比较对象的equals内容,从而决定是否存储该对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值