Guava Cache本地缓存
Guava介绍
Guava是一种基于开源的Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。
这个库是为了方便编码,并减少编码错误。
这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。
Guava Cache适用场景
1 消耗一些内存空间来提升速度;
2 缓存中存放的数据总量不会超出内存容量。
(Guava Cache是单个应用运行时的本地缓存,不把数据存放到文件或外部服务器(Memcached, Redis))
Guava Cache介绍
数据结构:ConcurrentHash (The returned cache is implemented as a hash table with similar performance characteristics to ConcurrentHashMap
.)
主要特性(详见下面的相关链接):
1 自动加载
2 回收策略:
2.1 基于容量
2.2 基于存活时间
2.3 基于权重
2.4 基于引用
3 移除监听器
4 缓存访问统计
主要接口:CacheBuilder, LoadingCache, CacheStats
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | public class CacheProTest { LoadingCache<Long, Person> cache; private int cacheTimeoutSeconds = 10 ; // 10秒 Integer counter = 1 ; @Before public void initialize() { System.out.println( "初始化" ); cache = CacheBuilder.newBuilder() /* 回收策略:基于容量(least-recently-used eviction when a maximum size is exceeded) */ .maximumSize( 10 ) // .initialCapacity(initialCapacity) /* 回收策略:基于存活时间(time-based expiration of entries, measured since last access or last write) */ .expireAfterWrite(cacheTimeoutSeconds, TimeUnit.SECONDS) // .expireAfterAccess(duration, unit) // .refreshAfterWrite(duration, unit) /* 回收策略:基于权重 */ // .maximumWeight(maximumWeight) // .weigher(weigher) /* 回收策略:基于引用(keys automatically wrapped in weak references, values automatically wrapped in weak or soft references)*/ // .weakKeys() // .weakValues() // .softValues() // 设置并发数为5,即同一时间最多只能有5个线程往cache执行写入操作 // .concurrencyLevel(concurrencyLevel) /* 缓存访问统计(accumulation of cache access statistics) */ .recordStats() /* 移除监听器(notification of evicted (or otherwise removed) entries) */ // .removalListener(listener) .build( new CacheLoader<Long, Person>() { /* 自动加载(automatic loading of entries into the cache) */ @Override public Person load(Long id) throws Exception { System.out.println( "获取值, id=" + id); // 调用接口获取值 Person p = new Person(); p.setId(id); p.setName( "name" + counter.toString()); counter++; return p; } }); } @Test public void test1() { try { /* 获值 */ // ConcurrentMap<Long, Person> asMap = cache.asMap(); // cache.get(key); // // cache.getAll(keys); // cache.getIfPresent(key); // cache.getAllPresent(keys); // cache.size(); /* 存值 */ // cache.put(key, value); // cache.putAll(m); // Map<? extends K, ? extends V> m /* 移除/删除 */ // cache.refresh(key); // cache.invalidate(key); // cache.invalidateAll(); // cache.invalidateAll(keys); // cache.cleanUp(); /* 缓存访问统计 */ CacheStats stats = cache.stats(); stats.averageLoadPenalty(); stats.evictionCount(); stats.hitCount(); stats.hitRate(); stats.loadCount(); stats.loadExceptionCount(); stats.loadExceptionRate(); stats.loadSuccessCount(); stats.missCount(); stats.missRate(); stats.requestCount(); stats.totalLoadTime(); } catch (Exception e) { e.printStackTrace(); } } @Test public void test2() { try { Long id = 1L; Person person1 = cache.get(id); Thread.sleep(3L * 1000L); Person person2 = cache.get(id); Thread.sleep(11L * 1000L); Person person3 = cache.get(id); System.out.println(person1); System.out.println(person2); System.out.println(person3); } catch (Exception e) { e.printStackTrace(); } } } class Person implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } @Override public String toString() { return JSON.toJSONString( this ); } } |
Guava Cache使用时需要关注的点
1 了解LoadingCache.refresh
正如LoadingCache.refresh(K)所声明,刷新表示为键加载新值,这个过程可以是异步的。
在刷新操作进行时,缓存仍然可以向其他线程返回旧值,而不像回收操作,读缓存的线程必须等待新值加载完成。
如果刷新过程抛出异常,缓存将保留旧值,而异常会在记录到日志后被丢弃[swallowed]。
重载CacheLoader.reload(K, V)可以扩展刷新时的行为,这个方法允许开发者在计算新值时使用旧的值。
2 了解 清理时机
使用CacheBuilder构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。
它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话。
因此使用LoadingCache.size() 一定要关注这个点。
相关链接
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步