com.github.javaclub.sword.cache.caffeine.CaffeineCache Maven / Gradle / Ivy
The newest version!
/*
* @(#)CaffeineCache.java 2020年6月30日
*
* Copyright (c) 2020. All Rights Reserved.
*
*/
package com.github.javaclub.sword.cache.caffeine;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.github.javaclub.Constants.CacheConfig;
import com.github.javaclub.Constants.MemCapacity;
import com.github.javaclub.sword.cache.LocalMemoryCache;
import com.github.javaclub.sword.core.Maps;
import com.github.javaclub.sword.core.Numbers;
import com.github.javaclub.toolbox.conf.CompositeAppConfigProperties;
import com.github.javaclub.toolbox.thread.ExecutorServiceInstance;
import com.github.javaclub.toolbox.thread.memlimit.MemoryLimitCalculator;
/**
* CaffeineCache
*
* @author Gerald Chen
* @version $Id: CaffeineCache.java 2020年6月30日 15:44:52 Exp $
*/
public abstract class CaffeineCache implements LocalMemoryCache {
private static final Logger log = LoggerFactory.getLogger(CaffeineCache.class);
protected LoadingCache mCache;
protected AtomicBoolean monitorInited = new AtomicBoolean(false);
/**
* 为JVM预设保留的空闲内存,当JVM剩余可用内存小于此值时,不允许提交新Element
*/
protected long maxFreeMemory = MemCapacity.intBytesOfKB(512);
public CaffeineCache() {
mCache = Caffeine.newBuilder()
.maximumSize(10000)
.recordStats() // 开启缓存统计
.build(new CacheLoader() {
@Override
public @Nullable V load(@NonNull K key) throws Exception {
return loadData(key);
}
});
this.monitorCacheStats();
}
public CaffeineCache(long maxSize, long duration, TimeUnit timeUnit) {
mCache = Caffeine.newBuilder()
.maximumSize(maxSize)
.recordStats() // 开启缓存统计
.refreshAfterWrite(duration, timeUnit)
.build(new CacheLoader() {
@Override
public @Nullable V load(@NonNull K key) throws Exception {
return loadData(key);
}
});
this.monitorCacheStats();
}
public abstract V loadData(K key);
boolean isStatslogEnabled() {
return CompositeAppConfigProperties.getInstance().boolValue(CacheConfig.CACHE_STATLOG_ENABLED);
}
protected void monitorCacheStats() {
if (monitorInited.compareAndSet(false, true)) {
ExecutorServiceInstance.get().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (log.isInfoEnabled() && isStatslogEnabled()) {
CacheStats stats = stats();
String hitRatePercent = Numbers.formatPercent(stats.hitRate(), 2, 2);
log.info("CacheStatsInfo: hitRate={}, stats={}", hitRatePercent, stats.toString());
}
}
}, 60L, 20L, TimeUnit.SECONDS);
}
}
public Map presentAll() {
return Maps.returnEmptyIfNull(null == mCache ? new ConcurrentHashMap() : mCache.asMap());
}
@Override
public boolean hasRemainedMemory() {
return MemoryLimitCalculator.maxAvailable() > maxFreeMemory;
}
@Override
public V getCache(K key) {
return mCache.get(key);
}
@Override
public void refresh(K key) {
mCache.refresh(key);
}
@Override
public void put(K key, V value) {
mCache.put(key, value);
}
@Override
public void remove(K key) {
mCache.invalidate(key);
}
public CacheStats stats() {
return mCache.stats();
}
}