Guava cache

Caching is an indispensable way to solve performance problems in our daily development. Simply put, cache is a piece of memory space opened up to improve system performance.

  The main function of the cache is to temporarily store the data processing results of the business system in memory and wait for the next access. In many occasions of daily development, due to the limitation of the performance of hard disk IO or the data processing and acquisition of our own business system, it may be very time-consuming. When we find that our system has a large amount of data requests, frequent IO and frequent IO Logic processing can lead to bottlenecks in hard disk and CPU resources. The function of the cache is to store these difficult data in the memory. When other threads or clients need to query the same data resources, the data is directly returned from the cached memory block, which can not only improve the response time of the system, but also It can also save the resource consumption of the data processing process, and overall, the system performance will be greatly improved.

  Caching is widely used in many systems and architectures, such as:

  1. CPU cache
  2. Operating system cache
  3. Local cache
  4. Distributed cache
  5. HTTP cache
  6. Database cache
  Wait, it can be said that in the field of computer and network, cache is everywhere. It can be said that as long as there is asymmetric hardware performance, there will be caches where network transmission is involved.

  Guava Cache is a full-memory local cache implementation that provides a thread-safe implementation mechanism. Overall, Guava cache is the best choice for local caching, easy to use and good performance.

  Guava Cache can be created in two ways:

  1. cacheLoader
  2. callable callback

  The difference between the cache created by these two methods and the way of using map to cache is that both methods implement a logic - get the value of key X from the cache, if the value has been cached , the value in the cache is returned. If it has not been cached, this value can be obtained through a method. But the difference is that the definition of cacheloader is relatively broad, and it is defined for the entire cache, which can be considered as a unified method of loading value according to the key value. The callable method is more flexible, allowing you to specify it when you get it.

  CacheLoader implementation example:

copy code
    @Test
    public void TestLoadingCache() throws Exception{
        LoadingCache<String,String> cahceBuilder=CacheBuilder
        .newBuilder()
        .build(new CacheLoader<String, String>(){
            @Override
            public String load(String key) throws Exception {        
                String strProValue="hello "+key+"!";                
                return strProValue;
            }
            
        });        
        
        System.out.println("jerry value:"+cahceBuilder.apply("jerry"));
        System.out.println("jerry value:"+cahceBuilder.get("jerry"));
        System.out.println("peida value:"+cahceBuilder.get("peida"));
        System.out.println("peida value:"+cahceBuilder.apply("peida"));
        System.out.println("lisa value:"+cahceBuilder.apply("lisa"));
        cahceBuilder.put("harry", "ssdded");
        System.out.println("harry value:"+cahceBuilder.get("harry"));
    }
copy code

  output:

copy code
jerry value:hello jerry!
jerry value:hello jerry!
peida value:hello peida!
peida value:hello peida!
lisa value:hello lisa!
harry value:ssdded
copy code

  Implementation of callable callback:

copy code
    @Test
    public void testcallableCache()throws Exception{
        Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();  
        String resultVal = cache.get("jerry", new Callable<String>() {  
            public String call() {  
                String strProValue="hello "+"jerry"+"!";                
                return strProValue;
            }  
        });  
        System.out.println("jerry value : " + resultVal);
        
        resultVal = cache.get("peida", new Callable<String>() {  
            public String call() {  
                String strProValue="hello "+"peida"+"!";                
                return strProValue;
            }  
        });  
        System.out.println("peida value : " + resultVal);  
    }

  output:
  jerry value : hello jerry!
  peida value : hello peida!
copy code

   Parameter description of cache:

  Recycling parameters:
  1. Size setting: CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(long)
  2. Time: expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)
  3. Reference: CacheBuilder. weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues()
  4. Explicit removal: invalidate(key) invalidateAll(keys) invalidateAll()
  5. Remove listener: CacheBuilder.removalListener(RemovalListener)
  

  Refresh mechanism:
  1. LoadingCache.refresh(K) When a new value is generated, the old value will still be used.
  2. CacheLoader.reload(K, V) allows the old value to be used in the process of generating a new value
  3. CacheBuilder.refreshAfterWrite(long, TimeUnit) automatically refreshes the cache

   Generic-based implementation:

copy code
    /**
     * No need for delayed processing (generic way encapsulation)
     * @return
     */
    public  <K , V> LoadingCache<K , V> cached(CacheLoader<K , V> cacheLoader) {
          LoadingCache<K , V> cache = CacheBuilder
          .newBuilder()
          .maximumSize(2)
          .weakKeys()
          .softValues ​​()
          .refreshAfterWrite(120, TimeUnit.SECONDS)
          .expireAfterWrite(10, TimeUnit.MINUTES)        
          .removalListener(new RemovalListener<K, V>(){
            @Override
            public void onRemoval(RemovalNotification<K, V> rn) {
                System.out.println(rn.getKey() + "removed" );  
                
            }})
          .build (cacheLoader);
          return cache;
    }
    
    /**
     * Get value by key
     * Calling method commonCache.get(key) ; return String
     * @param key
     * @return
     * @throws Exception
     */
  
    public  LoadingCache<String , String> commonCache(final String key) throws Exception{
        LoadingCache<String , String> commonCache= cached(new CacheLoader<String , String>(){
                @Override
                public String load(String key) throws Exception {
                    return "hello "+key+"!";    
                }
          });
        return commonCache;
    }
    
    @Test
    public void testCache() throws Exception{
        LoadingCache<String , String> commonCache=commonCache("peida");
        System.out.println("peida:"+commonCache.get("peida"));
        commonCache.apply("harry");
        System.out.println("harry:"+commonCache.get("harry"));
        commonCache.apply("lisa");
        System.out.println("lisa:"+commonCache.get("lisa"));
    }
copy code

  output:

peida: hello peida! 
harry: hello harry !
peida is removed
lisa:hello lisa!

  Generic-based Callable Cache implementation:

copy code
    private static Cache<String, String> cacheFormCallable = null; 

    
    /**
     * This mechanism can be used for those that require delayed processing; (generic packaging)
     * @param <K>
     * @param <V>
     * @param key
     * @param callable
     * @return V
     * @throws Exception
     */
    public static <K,V> Cache<K , V> callableCached() throws Exception {
          Cache<K, V> cache = CacheBuilder
          .newBuilder()
          .maximumSize(10000)
          .expireAfterWrite(10, TimeUnit.MINUTES)
          .build();
          return cache;
    }

    
    private String getCallableCache( final String userName) {
            try {
              // Callable will only call 
             return cacheFormCallable.get(userName, new Callable<String> () { if the cached value does not exist
                @Override
                public String call() throws Exception {
                    System.out.println(userName+" from db");
                    return "hello "+userName+"!";
               }
              });
           } catch (ExecutionException e) {
              e.printStackTrace ();
              return null;
            }
    }
    
    @Test
    public void testCallableCache() throws Exception{
         final String u1name = "peida";
         final String u2name = "jerry"; 
         final String u3name = "lisa"; 
         cacheFormCallable=callableCached();
         System.out.println("peida:"+getCallableCache(u1name));
         System.out.println("jerry:"+getCallableCache(u2name));
         System.out.println("lisa:"+getCallableCache(u3name));
         System.out.println("peida:"+getCallableCache(u1name));
         
    }
copy code

  output:

copy code
peida from db
Hide: Hello Hide !
jerry from db
jerry:hello jerry!
lisa from db
lisa: hello lisa ! 
Hide: Hello Hide !
copy code

  Description: Callable will only be called when the cached value does not exist, for example, the second call to getCallableCache(u1name) directly returns the value in the cache

  Guava Cache data removal:

  The data removal method when guava is used as a cache, the data removal in guava is divided into passive removal and active removal.
  The way to passively remove data, guava provides three ways by default:
  1. Size-based removal: You can see that it is removed according to the size of the cache. If it is about to reach the specified size, it will be less commonly used. The key-value pair is removed from the cache.
  The way of definition is generally CacheBuilder.maximumSize(long), and there is a method that can calculate the weight. I personally think that it is not used in actual use. As far as this common usage is concerned, there are several points to note.
    First, this size refers to the number of entries in the cache, not the memory size or other
    ; The system will start to remove the data when it is close to this size;
    thirdly, if a key-value pair has been removed from the cache, when you request access again, if cachebuild uses cacheloader In this way, it will still take the value from the cacheloader again. If it does not, an exception will be thrown
  . 2. Time-based removal: Guava provides two time-based removal methods
    expireAfterAccess(long, TimeUnit) This method is to   remove
    expireAfterWrite(long, TimeUnit) according to how long after a key-value pair is last accessed
Removal:
  This removal method is mainly based on the garbage collection mechanism of Java. According to the reference relationship of the key or value , the
  active removal method of data is determined to be removed. There are three methods of active removal:
  1. Use Cache.invalidate(key) for individual removal
  2. Use Cache.invalidateAll(keys) for batch removal
  3. Use Cache.invalidateAll() to remove all
  If you need to take action when removing data, you can also define Removal Listener, but it should be noted that the behavior in the default Removal Listener is executed synchronously with the removal action. If you need to change it to an asynchronous form, you can consider using RemovalListeners.asynchronous(RemovalListener, Executor)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326323320&siteId=291194637
Recommended