1、Guava缓存
Guava Cache适用于如下场景:git
- 你愿意消耗一些内存空间来提高速度。
- 你预料到某些键会被查询一次以上。
- 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。若是这不符合你的需求,请尝试Redis这类工具)
仓库坐标以下:github
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency>
代码详细示例:缓存
@Data public class CacheVO { private String name; public CacheVO(String name) { this.name = name; } }
public class GuavaCacheMangerService { private static LoadingCache<String, CacheVO> cache; private static ExecutorService executorService = new ThreadPoolExecutor(8, 8, 8, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1204)); static { cache = CacheBuilder.newBuilder() // 缓存项在给定时间内没有被读/写访问,则回收。 .expireAfterAccess(500, TimeUnit.SECONDS) // 缓存项在给定时间内没有被写访问(建立或覆盖),则回收。 // 若是认为缓存数据老是在固定时候后变得陈旧不可用,这种回收方式是可取的。 .expireAfterWrite(500, TimeUnit.SECONDS) // 初始化容量大小 .initialCapacity(1024 * 100) // 缓存项的数目不超过固定值 .maximumSize(1024 * 100) // 能够为缓存增长自动刷新功能,配合CacheLoader reload使用 .refreshAfterWrite(1, TimeUnit.SECONDS) // 加载缓存 .build(new CacheLoader<String, CacheVO>() { // 单个加载,要么返回已经缓存的值,要么使用CacheLoader向缓存原子地加载新值。 @Override public CacheVO load(String s) throws Exception { return createCacheVO(s); } // 批量加载,对每一个不在缓存的键,getAll方法会单独调用CacheLoader.load来加载缓存项。 // 若是批量加载比多个单独加载更高效,你能够重载CacheLoader.loadAll来利用这一点。 @Override public Map<String, CacheVO> loadAll(Iterable<? extends String> keys) throws Exception { return createBatchCacheVOs(keys); } // 异步刷新加载新值,在刷新操做进行时,缓存仍然能够向其余线程返回旧值, // 而不像回收操做,读缓存的线程必须等待新值加载完成。 @Override public ListenableFuture<CacheVO> reload(String key, CacheVO oldValue) throws Exception { if (needRefresh()) { return Futures.immediateFuture(oldValue); } ListenableFutureTask<CacheVO> task = ListenableFutureTask.create(() -> {return createCacheVO(key);}); executorService.execute(task); return task; } }); } public static boolean needRefresh() { Random ra =new Random(); return (ra.nextInt(10) % 2) > 0 ? true : false; } public static CacheVO createCacheVO(String key){ return new CacheVO(key); } public static Map<String, CacheVO> createBatchCacheVOs(Iterable<? extends String> keys) { Map<String, CacheVO> result = new HashMap<>(); for (String key : keys) { result.put(key, new CacheVO(key)); } return result; } public static void main(String[] args) throws Exception{ // 单个获取 CacheVO cacheVO1 = cache.get("AA"); // 若是有缓存则返回;不然运算、缓存、而后返回,整个过程是阻塞的 // 在整个加载方法完成前,缓存项相关的可观察状态都不会更改。 CacheVO cacheVO2 = cache.get("BB", () -> {return createCacheVO("BB");}); List<String> list = new ArrayList<>(); list.add("CC"); list.add("DD"); // 批量获取 Map<String, CacheVO> cacheMap = cache.getAll(list); // 个别清除 cache.invalidate("AA"); // 批量清除 cache.invalidateAll(list); // 清除全部 cache.invalidateAll(); } }
2、Caffeine缓存
Caffeine是一种高性能的缓存库,是基于Java 8的最佳(最优)缓存框架,性能各方面优于guava。服务器
代码仓库以下:框架
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.4.0</version> </dependency>
代码详细示例以下:dom
public class CaffeineCacheMangerService { private static LoadingCache<String, CacheVO> cache; private static AsyncLoadingCache<String, CacheVO> asyncCache; private static AsyncLoadingCache<String, CacheVO> asyncCache1; private static ExecutorService executorService = new ThreadPoolExecutor(8, 8, 8, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1204)); static { cache = Caffeine.newBuilder() // 初始化缓存长度 .initialCapacity(1024 * 10) // 最大长度 .maximumSize(1024 * 10) // 更新策略 .refreshAfterWrite(10, TimeUnit.SECONDS) // 设置缓存的过时时间 .expireAfterWrite(10, TimeUnit.SECONDS) .build(new CacheLoader<String, CacheVO>() { // 同步加载 @CheckForNull @Override public CacheVO load(@Nonnull String key) throws Exception { return createCacheVO(key); } // getAll将会对缓存中没有值的key分别调用CacheLoader.load方法来构建缓存的值。 // 咱们能够重写CacheLoader.loadAll方法来提升getAll的效率。 @Nonnull @Override public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) throws Exception { return createBatchCacheVOs(keys); } }); // 异步加载 同步load写法,最后也会转异步 asyncCache = Caffeine.newBuilder() .maximumSize(1024 * 10) .expireAfterWrite(10, TimeUnit.SECONDS) .buildAsync(new CacheLoader<String, CacheVO>() { @CheckForNull @Override public CacheVO load(@Nonnull String key) throws Exception { return createCacheVO(key); } @Nonnull @Override public Map<String, CacheVO> loadAll(@Nonnull Iterable<? extends String> keys) { return createBatchCacheVOs(keys); } }); // 异步加载 异步load写法 asyncCache1 = Caffeine.newBuilder() .maximumSize(1024 * 10) .expireAfterWrite(10, TimeUnit.SECONDS) .buildAsync(new AsyncCacheLoader<String, CacheVO>() { @Nonnull @Override public CompletableFuture<CacheVO> asyncLoad(@Nonnull String key, @Nonnull Executor executor) { return asyncCreateCacheVO(key, executor); } @Nonnull @Override public CompletableFuture<Map<String, CacheVO>> asyncLoadAll(@Nonnull Iterable<? extends String> keys, @Nonnull Executor executor) { return asyncCreateBatchCacheVOs(keys, executor); } }); } public static CompletableFuture<CacheVO> asyncCreateCacheVO(String key, Executor executor) { return CompletableFuture.supplyAsync(() -> createCacheVO(key), executor); } public static CompletableFuture<Map<String, CacheVO>> asyncCreateBatchCacheVOs(Iterable<? extends String> keys, Executor executor) { return CompletableFuture.supplyAsync(() -> createBatchCacheVOs(keys),executor); } public static CacheVO createCacheVO(String key) { return new CacheVO(key); } public static Map<String, CacheVO> createBatchCacheVOs(Iterable<? extends String> keys) { Map<String, CacheVO> result = new HashMap<>(); for (String key : keys) { result.put(key, new CacheVO(key)); } return result; } public static void main(String[] args) throws Exception { CacheVO cacheVO1 = cache.get("AA"); List<String> list = new ArrayList<>(); list.add("BB"); list.add("CC"); Map<String, CacheVO> map = cache.getAll(list); // 若是有缓存则返回;不然运算、缓存、而后返回,整个过程是阻塞的 // 即便多个线程同时请求该值也只会调用一次Function方法 CacheVO cacheVO2 = cache.get("DD", (k) -> createCacheVO(k)); System.out.println(JSON.toJSONString(cacheVO2)); // 单个清除 cache.invalidate("AA"); // 批量清除 cache.invalidateAll(list); // 所有清除 cache.invalidateAll(); // 返回一个CompletableFuture CompletableFuture<CacheVO> future = asyncCache.get("EE"); CacheVO asyncCacheVO = future.get(); System.out.println(JSON.toJSONString(asyncCacheVO)); // 返回一个CompletableFuture<MAP<>> CompletableFuture<Map<String, CacheVO>> allFuture = asyncCache.getAll(list); Map<String, CacheVO> asyncMap = allFuture.get(); System.out.println(JSON.toJSONString(asyncMap)); CompletableFuture<CacheVO> future1 = asyncCache1.get("FF"); CacheVO asyncCacheVO1 = future1.get(); System.out.println(JSON.toJSONString(asyncCacheVO1)); CompletableFuture<Map<String, CacheVO>> allFuture1 = asyncCache1.getAll(list); Map<String, CacheVO> asyncMap1 = allFuture.get(); System.out.println(JSON.toJSONString(asyncMap1)); } }
3、堆外缓存
一、堆外内存是什么?
在JAVA中,JVM内存指的是堆内存。机器内存中,不属于堆内存的部分即为堆外内存。异步
- Unsafe类操做堆外内存
- NIO类操做堆外内存 代码示例:
// 反射获取Unsafe实例 Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe)f.get(null); // 分配一块内存空间 long address = unsafe.allocateMemory(1024); unsafe.putLong(address, 1); System.out.println(unsafe.getAddress(address)); // 释放内存 unsafe.freeMemory(address); // 经过nio包下的ByteBuffer直接分配内存 ByteBuffer buffer = ByteBuffer.allocateDirect(10 * 1024 * 1024);
二、堆外内存垃圾回收
参考下面连接: https://www.jianshu.com/p/35cf0f348275async
三、为何用堆外内存
本地缓存是很是快速的,可是大量的本地缓存会带来gc的压力,因此这个时候堆外内存是一个很好的选择。ide
四、堆外缓存(ohc)
仓库坐标以下:工具
<dependency> <groupId>org.caffinitas.ohc</groupId> <artifactId>ohc-core</artifactId> <version>0.7.0</version> </dependency>
代码示例以下:
public static OHCache<byte[], byte[]> ohcCache; static{ ohcCache = OHCacheBuilder.<byte[], byte[]>newBuilder() .keySerializer(new CacheSerializer<byte[]>() { @Override public void serialize(byte[] bytes, ByteBuffer byteBuffer) { byteBuffer.put(bytes); } @Override public byte[] deserialize(ByteBuffer byteBuffer) { return new byte[]{byteBuffer.get()}; } @Override public int serializedSize(byte[] bytes) { return bytes.length; } }) .valueSerializer(new CacheSerializer<byte[]>() { @Override public void serialize(byte[] bytes, ByteBuffer byteBuffer) { byteBuffer.putInt(bytes.length); byteBuffer.put(bytes); } @Override public byte[] deserialize(ByteBuffer byteBuffer) { byte[] arr = new byte[byteBuffer.getInt()]; byteBuffer.get(arr); return arr; } @Override public int serializedSize(byte[] bytes) { return bytes.length; } }) // number of segments (must be a power of 2), defaults to number-of-cores * 2 .segmentCount(2) // hash table size (must be a power of 2), defaults to 8192 .hashTableSize(1024) .capacity(2 * 1024 * 8) .timeouts(true) // 每一个段的超时插槽数 .timeoutsSlots(64) // 每一个timeouts-slot的时间量(以毫秒为单位) .timeoutsPrecision(512) // "LRU" 最旧的(最近最少使用的)条目被逐出 // "W_TINY_LFU" 使用频率较低的条目被逐出,以便为新条目腾出空间 .eviction(Eviction.W_TINY_LFU) .build(); }