After using the cache object ConcurrentLruCache, the key value cannot be hit, resulting in the failure to improve the system performance

Keywords: Java Spring Cache

1. Problem Description:

Concurrent lrucache is used as the JVM cache pool object

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

}

  As can be seen from the above code snippet, the cached KEY value is actually a user-defined object type, as shown below:

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

The above code shows the internal structure of the cache KEY value object, which is still relatively simple:

        (1) Two member variables are defined as condition parameters for retrieving data from the database.

        (2) The equals method is rewritten to determine whether an object should be added to the cache pool according to the content when it is added to the cache pool.

2. Problem analysis:

         Through the operation in step 1, there seems to be no problem on the surface, but in actual use, it is found that the cached KEY value does not hit directly, and the objects queried each time are DB queries.

          Why is the property value of the incoming object even if it is the same, but the cache pool object always thinks it is a new object? With this problem, if you go deep into ConcurrentLruCache itself, you will find that it uses ConcurrentHashMap to realize the storage mechanism. Since there is the shadow of HashMap, the problem is relatively clear. When HashMap stores an object, it first compares the HashCode value of the object. If the HashCode value is the same, it calls the equals method of the object to compare the content of the object.

        So far, I think the problem lies in the UserCacheKey   In itself, a very important method is ignored in this class, which is a sentence we often hear: "if you rewrite the equals method of the class, you'd better also rewrite the hashCode method of the class."

3. Problem solving:

The modified UserCacheKey is as follows:

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

Problem summary:

1. For a java object, the importance of its hashCode method, which is the first choice to determine whether the two objects are the same;

2. To deepen the understanding of HashMap storage mechanism, it first compares the hashcodes of the two objects, and then compares the equals content of the object to determine whether to store the object.

Posted by lisa3711 on Thu, 04 Nov 2021 22:15:27 -0700