简体   繁体   English

如何使用Guava的LoadingCache更新存储在缓存中的LinkedList值

[英]How to update a LinkedList value stored in cache using Guava's LoadingCache

I am trying to utilize LoadingCache from the Guava library to cache a LinkedList . 我正在尝试利用Guava库中的LoadingCache来缓存LinkedList

LoadingCache<Integer, LinkedList<String>> cache;

I've setup a CacheLoader to handle misses, which is working fine. 我已经设置了一个CacheLoader来处理未命中,这很正常。 However there is another system that needs to submit updates to existing cache entries. 但是,还有另一个系统需要提交现有缓存条目的更新。 Each update needs to be appended to the LinkedList and will arrive at a fairly quick rate (thousands per minute). 每个更新都需要附加到LinkedList并以相当快的速度(每分钟数千)到达。 Finally, it needs to be thread safe. 最后,它需要是线程安全的。

Here is a naive approach that illustrates the logic but is not thread safe: 这是一个简单的方法,说明了逻辑,但不是线程安全的:

public void add(Integer key, String value) {
    LinkedList<String> list = cache.get(key);
    list.add(value);
    cache.put(key, list);
}

Any advice on how to make this work? 有关如何使这项工作的任何建议? I can look at other libraries but Guava 14 is already a dependency of this codebase and would be very convenient. 我可以查看其他库,但Guava 14已经是这个代码库的依赖项,非常方便。

The last line in 最后一行

public void add(Integer key, String value) {
    LinkedList<String> list = cache.get(key);
    list.add(value);
    cache.put(key, list);
}

is not needed as you already modify the object obtained from the cache. 因为您已经修改了从缓存中获取的对象,所以不需要。 Maybe all you need is 也许你需要的只是

public void add(Integer key, String value) {
    LinkedList<String> list = cache.get(key);
    synchronized (list) {
        list.add(value);
    }
}

It depends on what eviction happens. 这取决于驱逐的发生。 If there's no eviction at all, then it will work. 如果根本没有驱逐,那么它将起作用。 If an entry can get evicted before the updating method finishes, then you're out of luck. 如果一个条目可以在更新方法完成之前被驱逐,那么你就不走运了。

Nonetheless, there's a simple solution: Using a global lock would work, but obviously inefficiently. 尽管如此,还是有一个简单的解决方案:使用全局锁定会起作用,但显然效率低下。 So use a list of locks: 所以使用锁列表:

private static final CONCURRENCY_LEVEL = 64; // must be power of two
List<Object> locks = Lists.newArrayList(); // an array would do as well
for (int i=0; i<CONCURRENCY_LEVEL; ++i) locks.add(new Object());

public void add(Integer key, String value) {
    synchronized (locks.get(hash(key))) {
        cache.get(key).add(value);
    }
}

where hash - depending on the distribution of your keys - can be as simple as key.intValue() & (CONCURRENCY_LEVEL-1) or something like here what sort of randomizes the distribution. 其中hash -根据您的密钥的分发-可以简单如key.intValue() & (CONCURRENCY_LEVEL-1)或类似的东西在这里什么样的会随机分配。


While my above list of locks should work, there's Striped.lock(int) in Guava, which makes it a bit simpler and takes care of padding (see false sharing for what it's good for) and whatever. 虽然我上面的锁定列表应该可以工作,但是在Guava中有Striped.lock(int) ,这使得它更简单并且可以处理填充(请参阅错误共享以获得它的优点)等等。


Most probably you should not use LinkedList as it's nearly always slower than ArrayList . 很可能你不应该使用LinkedList因为它几乎总是比ArrayList慢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM