繁体   English   中英

我应该使用哪个Java集合来实现线程安全缓存?

[英]Which Java collection should I use to implement a thread-safe cache?

我正在寻求实现一个简单的缓存而不需要做太多的工作(当然)。 在我看来,标准Java集合之一应该足够了,只需要一点额外的工作。 具体来说,我正在存储来自服务器的响应,密钥可以是请求URL字符串,也可以是从URL生成的哈希代码。

我原本以为我能够使用WeakHashMap ,但看起来这种方法迫使我管理我想要保留的对象,而且我没有用强引用管理的任何对象都会立即被扫除。 我应该尝试使用SoftReference值的ConcurrentHashMap吗? 或者那些也会被积极地清理干净?

我现在正在查看LinkedHashMap类。 通过一些修改,它看起来很有希望用于MRU缓存。 还有其他建议吗?

无论我使用哪个集合,我应该尝试手动修剪LRU值,还是可以信任VM偏向回收最近访问过的对象?

仅供参考,我正在Android上开发,所以我不想导入任何第三方库。 我正在处理一个非常小的堆(16到24 MB),因此VM可能非常渴望回收资源。 我认为GC会很有侵略性。

如果使用基于SoftReference的键,VM将(强烈)偏向最近访问的对象。 但是这将是非常难以确定缓存语义-唯一保证一个SoftReference的给你(在WeakReference的)是一个前被清除OutOfMemoryError被抛出。 对于JVM实现来说,将它们视为与WeakReferences完全相同是完全合法的,此时您最终可能会得到一个不缓存任何内容的缓存。

我不知道在Android上如何工作,但是使用Sun最近的JVM,可以使用-XX:SoftRefLRUPolicyMSPerMB命令行选项来调整SoftReference行为,该选项确定可以保留软可达对象的毫秒数,堆中的每MB可用内存。 正如您所看到的,这将是非常难以获得任何可预测的生命周期行为,更令人痛苦的是,此设置对于VM中的所有软引用是全局的,并且不能单独调整以用于各个类的使用SoftReferences(每次使用的机会都需要不同的参数)。


制作LRU缓存的最简单方法是扩展LinkedHashMap ,如此处所述 由于您需要线程安全性,最初扩展此方法的最简单方法是在此自定义类的实例上使用Collections.synchronizedMap以确保安全的并发行为。

注意过早优化 - 除非您需要非常高的吞吐量,否则理论上粗略同步的次优开销不太可能成为问题。 好消息 - 如果分析显示由于密码锁争用导致您执行速度太慢,您将获得有关缓存运行时使用的足够信息,您将能够提供合适的无锁替代方案(可能基于ConcurrentHashMap和一些手动LRU处理)而不必猜测其负载配置文件。

LinkedHashMap易于用于缓存。 这将创建一个大小为10的MRU缓存。

private LinkedHashMap<File, ImageIcon> cache = new LinkedHashMap<File, ImageIcon>(10, 0.7f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<File, ImageIcon> eldest) {
        return size() > 10;
    }
};

我猜你可以用这个LinkedHashMap的同步委托创建一个类。 如果我对同步的理解是错误的,请原谅我。

www.javolution.org有一些interestig功能 - 同步快速收集。 在你的情况下,它值得一试,因为它为Android设备提供了一些小巧的增强功能。

对于同步, Collections框架提供了一个同步映射:

Map<V,T> myMap = Collections.synchronizedMap(new HashMap<V, T>());

然后,您可以将其包装起来,或者在缓存对象中处理LRU逻辑。

我喜欢Apache Commons Collections LRUMap

暂无
暂无

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

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