我有一个LoadingCache<K,V>创建使用CacheBuilder:
LoadingCache<K,V> myCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES)
.maximumSize(500)
.build(someCacheLoader);
Run Code Online (Sandbox Code Playgroud)
我需要定期迭代缓存中的所有条目(键和值).我知道我可以使用LoadingCache#asMap(),并且:
Map#entrySet(),或者Map#keySet(),明确Map#get(Object)的值.在前一种情况下:
for (Map.Entry<K, V> entry : myCache.asMap().entrySet()) {
K key = entry.getKey();
V value = entry.getValue();
doSomeWorkOn(key, value);
}
Run Code Online (Sandbox Code Playgroud)
这会更新缓存中每个条目的访问时间吗?我已经CacheBuilder#expireAfterAccess(long, TimeUnit)非常仔细地阅读了JavaDoc ,但在这种情况下发现它是模棱两可的/不清楚的:
指定在创建条目,最近替换其值或上次访问后经过固定持续时间后,应自动从缓存中删除每个条目.所有缓存读写操作(包括
Cache.asMap().get(Object)和Cache.asMap().put(K, V))都会重置访问时间,但不会通过集合视图上的操作重置访问时间Cache.asMap.
显然,我提到的第二种迭代方式确实会重置访问时间,但我想知道第一种方式是什么行为.
Mar*_*ers 15
我会解释这个:
(...)但不是通过Cache.asMap的集合视图上的操作
指entrySet,keySet和values.这是a的三个集合视图Map.因此,使用它们不应导致访问.
以下是JUnit(+ Mockito)测试,显示每种情况下的行为.通过读值entrySet或values不不阻止删除的条目(也没有从阅读键entrySet或keySet).asMap().get()正如文档所指定的那样,阅读使用会被视为访问权限.
private Ticker ticker = Mockito.mock(Ticker.class);
@SuppressWarnings({"unchecked"})
private RemovalListener<String, String> removalListener = Mockito.mock(RemovalListener.class);
private Cache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.SECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build();
Run Code Online (Sandbox Code Playgroud)
entrySet@Test
public void testEntrySetAccessDoesNotCountAsAccess() {
//write
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
cache.put("foo", "bar");
//read
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
cache.asMap().entrySet().iterator().next().getValue();
cache.asMap().entrySet().iterator().next().getKey();
//maintenance
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
cache.cleanUp();
verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}
Run Code Online (Sandbox Code Playgroud)
keySet@Test
public void testKeySetAccessDoesNotCountAsAccess() {
//write
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
cache.put("foo", "bar");
//read
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
cache.asMap().keySet().iterator().next();
//maintenance
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
cache.cleanUp();
verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}
Run Code Online (Sandbox Code Playgroud)
values@Test
public void testValuesAccessDoesNotCountAsAccess() {
//write
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
cache.put("foo", "bar");
//read
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
cache.asMap().values().iterator().next();
//maintenance
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
cache.cleanUp();
verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}
Run Code Online (Sandbox Code Playgroud)
asMap().get()@Test
public void testMapGetAccessCountsAsAccess() {
//write
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
cache.put("foo", "bar");
//read
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
cache.asMap().get("foo");
//maintenance
when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
cache.cleanUp();
verify(removalListener, never()).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4690 次 |
| 最近记录: |