我正在尝试使用番石榴缓存作为ConcurrentLinkedHashMap的替代品。但是我发现虽然ConcurrentLinkedHashMap允许我按照Insertion的顺序迭代地图,但是Guava的asMap()
方法不会以任何特定的顺序返回元素。我错过了什么,或者这个功能根本不可用?
示例(尝试打印键,值和条目):
Cache<Integer, Integer> cache = CacheBuilder.newBuilder().maximumSize(10).initialCapacity(10)
.expireAfterAccess(10000, TimeUnit.SECONDS).build();
cache.put(1, 1);
cache.put(2, 2);
cache.put(3, 3);
cache.put(4, 4);
cache.put(5, 5);
cache.put(6, 6);
Iterator<Integer> iter1 = cache.asMap().keySet().iterator();
System.out.println("Keys");
while (iter1.hasNext())
System.out.println(iter1.next());
System.out.println("Values");
Iterator<Integer> iter2 = cache.asMap().values().iterator();
while (iter2.hasNext())
System.out.println(iter2.next());
System.out.println("Entries");
Iterator<Entry<Integer, Integer>> iter3 = cache.asMap().entrySet().iterator();
while (iter3.hasNext())
{
Entry<Integer,Integer> entry = iter3.next();
System.out.println(entry.getKey() + " " + entry.getValue());
}
打印:
Keys
2
6
1
4
3
5
Values
2
6
1
4
3
5
Entries
2 2
6 6
1 1
4 4
3 3
5 5
答案 0 :(得分:2)
(回答我自己的问题)
似乎fge的答案是正确的,并且Guava Cache无法根据插入顺序进行迭代。作为一种解决方法,我使用了之前提到的ConcurrentLinkedHashMap,它功能较少,但允许有序迭代。
我仍然感谢Guava团队成员的官方回答,因为这似乎表明ConcurrentLinkedHashMap没有完全集成到Guava中(与ConcurrentLinkedHashMap文档相反)
答案 1 :(得分:2)
CacheWriter
将允许在显式写入或删除期间调用您的代码。对于加载缓存,您必须在加载器中执行相同的工作。这也是在条目锁定下执行的,因此您可以假设原子性。这可以让您在不依赖缓存的内部数据结构的情况下维护顺序。请注意,如果执行有序迭代时的工作很昂贵,您可能希望将其复制到锁内,然后在外部进行工作,以免阻止缓存写入。
LinkedHashMap<K, V> orderedMap = new LinkedHashMap<>();
LoadingCache<K, V> cache = Caffeine.newBuilder()
.writer(new CacheWriter<K, V>() {
public void write(K key, V value) {
synchronized (orderedMap) {
orderedMap.put(key, value);
}
}
public void delete(K key, V value, RemovalCause cause) {
if (cause == RemovalCause.REPLACED) {
return;
}
synchronized (orderedMap) {
orderedMap.remove(key);
}
}
})
.maximumSize(1_000)
.build(key -> {
V value = ...
synchronized (orderedMap) {
orderedMap.put(key, value);
}
return value;
});
cache.put(key1, value); // calls writer under lock
cache.get(key2); // calls loader under lock; not writer
cache.invalidate(key1); // calls writer under lock
cache.policy().eviction().get().setMaximum(0); // calls writer under lock
synchronized (orderedMap) {
for (K key : orderedMap.keySet()) {
// do work, but blocks writes!
}
}