All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy