是否可以按插入/访问顺序迭代番石榴缓存?

时间:2014-02-23 10:01:27

标签: java caching map guava

我正在尝试使用番石榴缓存作为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

2 个答案:

答案 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!
  }
}