Google, Guava efficient local cache

Guva google is a public open source java library, like Apache Commons, which provides a collection of some reflection, cache, scientific computing, xml, io libraries and other tools.
just one cache module. You can easily and quickly build local cache using Guva cache.

Construction of a cache using the Guava

First need to add guava rely on maven project

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>25.0-jre</version>
</dependency>

Creating a cache using the Guava

// 通过CacheBuilder构建一个缓存实例
Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(100) // 设置缓存的最大容量
                .expireAfterWrite(1, TimeUnit.MINUTES) // 设置缓存在写入一分钟后失效
                .concurrencyLevel(10) // 设置并发级别为10
                .recordStats() // 开启缓存统计
                .build();
// 放入缓存
cache.put("key", "value");
// 获取缓存
String value = cache.getIfPresent("key");

Direct fail within a certain time expireAfterWrite cache
expireAfterAccess cache after being accessed, after a certain time has expired
getIfPresent there is no return null


It illustrates the use of Guava creates a memory-based local cache, the cache and specify a number of parameters such as cache size, cache expiration time, concurrency level, etc., and then put into a cache by using the method and getIfPresent to get it.

Cache与LoadingCache

Cache is constructed by a method of CacheBuilder Build (), which is provided Gauva basic cache interface, and it provides some common cache api:

Cache<Object, Object> cache = CacheBuilder.newBuilder().build();
// 放入/覆盖一个缓存
cache.put("k1", "v1");
// 获取一个缓存,如果该缓存不存在则返回一个null值
Object value = cache.getIfPresent("k1");
// 获取缓存,当缓存不存在时,则通Callable进行加载并返回。该操作是原子
Object getValue = cache.get("k1", new Callable<Object>() {
    @Override
    public Object call() throws Exception {
        return null;
    }
});

LoadingCache

LoadingCache inherited from Cache, when building LoadingCache, you need CacheBuilder of build (CacheLoader <? Super K1, V1> loader) was constructed

CacheBuilder.newBuilder()
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                // 缓存加载逻辑
                ...
            }
        });

It can load the cache by spontaneous CacheLoader

LoadingCache<Object, Object> loadingCache = CacheBuilder.newBuilder().build(new CacheLoader<Object, Object>() {
            @Override
            public Object load(Object key) throws Exception {
                return null;
            }
        });
// 获取缓存,当缓存不存在时,会通过CacheLoader自动加载,该方法会抛出ExecutionException异常
loadingCache.get("k1");
// 以不安全的方式获取缓存,当缓存不存在时,会通过CacheLoader自动加载,该方法不会抛出异常
loadingCache.getUnchecked("k1");

Cache concurrency level

Guava offers a set of concurrent level api, so that the cache supports concurrent read and write. Similar Guava cache with concurrent ConcurrentHashMap also achieved by separating the lock. In general, the level is set to concurrency server cpu cores is a relatively good choice.

CacheBuilder.newBuilder()
        // 设置并发级别为cpu核心数
        .concurrencyLevel(Runtime.getRuntime().availableProcessors()) 
        .build();

The initial size of the cache

When we build a cache to cache may set a reasonable size of the initial capacity, due to the cache using the Guava separate lock mechanism, the expansion cost is very expensive. Therefore, a reasonable initial capacity can reduce the number of cache expansion vessel.

CacheBuilder.newBuilder()
        // 设置初始容量为100
        .initialCapacity(100)
        .build();

When using recovery strategy based on the maximum capacity, we need to set up two essential parameters:

  • maximumWeigh; specifies the maximum capacity.
  • Weigher; buffer capacity used to calculate the size of the cache during loading.

Here we include a key and value are of type String cache:

CacheBuilder.newBuilder()
        .maximumWeight(1024 * 1024 * 1024) // 设置最大容量为 1M
        // 设置用来计算缓存容量的Weigher
        .weigher(new Weigher<String, String>() { 
            @Override
            public int weigh(String key, String value) {
                return key.getBytes().length + value.getBytes().length;
            }
        }).build();

When the maximum number of cache / approaching or exceeding the maximum capacity of our set, Guava LRU algorithm will be used to cache before recycling.

Based Soft recovery / weak references

Based on the recovery policy reference, and is unique in java. There are objects automatic recovery mechanism, according to the way programmers to create different objects, the objects referenced by the strong to the weak into strong, soft references, weak references, phantom references in java. For these types of references them with the following differences


** ** strong references

Strong references are most commonly used reference. If an object has a strong reference, and that the garbage collector will never recover it.

Object o=new Object();   //  强引用 

When insufficient memory space, the garbage collector does not automatically reclaim a strong reference to the object referenced, but will direct throw OutOfMemoryError error, the abnormal program termination.

Soft references

Relative to the strong references, soft references is an unstable reference, if an object has a soft references, when memory is ample, GC will not take the initiative to recycle soft reference object, while the soft reference object when memory will be reclaimed.

SoftReference<Object> softRef=new SoftReference<Object>(new Object()); // 软引用
Object object = softRef.get(); // 获取软引用

Use soft references to prevent memory leaks, and enhance the robustness of the program. But be sure to do null detection.

Weak references

A weak reference is a soft quote more volatile than the reference, because regardless of whether sufficient memory, weak referenced objects are likely to be recovered.

WeakReference<Object> weakRef = new WeakReference<Object>(new Object()); // 弱引用
Object obj = weakRef.get(); // 获取弱引用

False quote

The phantom reference that reference is useless, because if a phantom reference object holds only, and then it does not have any references to the same. Hardly used in practice.

Guava cache support, the soft / weak recovery of the cache reference. Using this method can greatly improve memory utilization, and memory overflow exception does not occur.

CacheBuilder.newBuilder()
        .weakKeys() // 使用弱引用存储键。当键没有其它(强或软)引用时,该缓存可能会被回收。
        .weakValues() // 使用弱引用存储值。当值没有其它(强或软)引用时,该缓存可能会被回收。
        .softValues() // 使用软引用存储值。当内存不足并且该值其它强引用引用时,该缓存就会被回收
        .build();

By soft / weak recovery by reference, equivalent to cache recovery task to GC, so that the cache hit rate becomes very unstable, in the case of non-essential, or recommendations based on the number and capacity of recovery.

Explicit recovery

After the finished building the cache, we can provide the interface through Cache, explicit cache recovery, for example:

// 构建一个缓存
Cache<String, String> cache = CacheBuilder.newBuilder().build();
// 回收key为k1的缓存
cache.invalidate("k1");
// 批量回收key为k1、k2的缓存
List<String> needInvalidateKeys = new ArrayList<>();
needInvalidateKeys.add("k1");
needInvalidateKeys.add("k2");
cache.invalidateAll(needInvalidateKeys);
// 回收所有缓存
cache.invalidateAll();

And refresh the cache expiration policy

Guava also provides a cache expiration policy and refresh policy.

Cache expiration policy

Cache expiration policy is divided into fixed and relative time.

Fixed time generally refers to how long after writing expired, for example, we built a write cache expires after 10 minutes:

CacheBuilder.newBuilder()
        .expireAfterWrite(10, TimeUnit.MINUTES) // 写入10分钟后过期
        .build();

// java8后可以使用Duration设置
CacheBuilder.newBuilder()
        .expireAfterWrite(Duration.ofMinutes(10))
        .build();

Relative time is usually relative to the access time, that is, after each visit will refresh the cache expiration time, which is somewhat similar to the servlet session expiration time, for example, to build a cache access is not expire within 10 minutes:

CacheBuilder.newBuilder()
        .expireAfterAccess(10, TimeUnit.MINUTES) //在10分钟内未访问则过期
        .build();

// java8后可以使用Duration设置
CacheBuilder.newBuilder()
        .expireAfterAccess(Duration.ofMinutes(10))
        .build();

Cache Refresh

Regularly updated and supports explicit Guava cache refresh two ways in which the timing of refresh can be performed only LoadingCache.

Regularly updated

When making a cache regularly updated, we need to specify the cache refresh interval, and is used to load a cache CacheLoader, when the refresh interval is reached, the next cache acquisition, calls the load method CacheLoader refresh the cache. Construction of a refresh rate of, for example, 10 minutes cache:

CacheBuilder.newBuilder()
        // 设置缓存在写入10分钟后,通过CacheLoader的load方法进行刷新
        .refreshAfterWrite(10, TimeUnit.SECONDS)
        // jdk8以后可以使用 Duration
        // .refreshAfterWrite(Duration.ofMinutes(10))
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                // 缓存加载逻辑
                ...
            }
        });
 

Explicit refresh

After the cache building is complete, we can excuse some of the methods provided by the Cache, explicit cache refresh coverage, such as:

// 构建一个缓存
Cache<String, String> cache = CacheBuilder.newBuilder().build();
// 使用put进行覆盖刷新
cache.put("k1", "v1");
// 使用Map的put方法进行覆盖刷新
cache.asMap().put("k1", "v1");
// 使用Map的putAll方法进行批量覆盖刷新
Map<String,String> needRefreshs = new HashMap<>();
needRefreshs.put("k1", "v1");
cache.asMap().putAll(needRefreshs);
// 使用ConcurrentMap的replace方法进行覆盖刷新
cache.asMap().replace("k1", "v1");

For LoadingCache, due to its ability to automatically load the cache, so refresh is performed, no explicit cache incoming values:

LoadingCache<String, String> loadingCache = CacheBuilder
            .newBuilder()
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {
                    // 缓存加载逻辑
                    return null;
                }
            });
// loadingCache 在进行刷新时无需显式的传入 value
loadingCache.refresh("k1");

Original: https://rumenz.com/rumenbiji/google-guava-java.html

Guess you like

Origin www.cnblogs.com/rumenz/p/11709085.html