用于少量写入和频繁读取的Java Concurrent集合

时间:2016-12-15 22:06:57

标签: java multithreading java.util.concurrent concurrentskiplistmap

我想使用基于比较器的键值Map。这将具有读取和罕见的写入操作(通过调度程序每3个月一次)。集合的初始加载将在应用程序启动时完成。 另请注意,写入将:

  • 向地图添加一个条目
  • 不会修改任何现有的地图条目。

ConcurrentSkipListMap是否适合这个。对此进行get操作是否允许同时访问多个线程?我正在寻找并发非阻塞读取但是原子写入。

3 个答案:

答案 0 :(得分:1)

如果您愿意尝试第三方代码,您可以考虑写入时复制版本的地图,这对于不经常写入非常理想。这是通过谷歌搜索出现的一个:

https://bitbucket.org/atlassian/atlassian-util-concurrent/wiki/CopyOnWrite%20Maps

从未尝试过这样做,所以请注意。

答案 1 :(得分:0)

ConcurrentHashMap正是您所寻找的。来自Javadoc:

  

检索操作(包括get)一般不会阻塞,因此可能与更新操作重叠(包括put和remove)。检索反映了最近完成的更新操作的结果。 (更正式地说,给定密钥的更新操作与报告更新值的该密钥的任何(非空)检索之前发生关系。)

听起来它满足了“并发非阻塞读取但原子写入”的要求。

由于你写的这么少,你可能想要指定一个high loadFactor and appropriate initialSize when creating the ConcurrentHashMap,这会在你填充地图时阻止表调整大小,尽管这是一个适度的好处。 (您也可以将concurrencyLevel设置为1,尽管Java 8的Javadoc似乎暗示不再将其用作大小调整提示。)

如果绝对必须 SortedMapNavigableMap,那么ConcurrentSkipListMap就是开箱即用的方式。但是在使用它们之前,我会仔细检查你确实需要这些接口提供的功能(获取第一个/最后一个键,子图,查找附近的条目等)。您将支付高昂的价格(对于大多数操作,记录n与恒定时间)。

答案 2 :(得分:0)

由于您正在寻找并发操作,因此您基本上有3个竞争对手。 Hashtable,ConcurrentHashMap,ConcurrentSkipListMap(或Collections.synchronizedMap()但效率不高)。

  • 其中3个后者更适合并发操作,因为它们只是锁定地图的一部分而不是像Hashtable一样锁定整个地图。
  • 在后两个中,SkipListMap使用跳过列表数据结构,确保了快速搜索和各种操作的平均O(log n)性能。
  • 它还提供了ConcurrentHashMap无法执行的操作,即ceilingEntry / Key(),floorEntry / Key()等。它还维护一个必须计算的排序顺序。

因此,如果您只是要求更快的搜索,我建议使用ConcurrentHashMap,但由于您还提到了'罕见的写操作'和'所需的排序'顺序,我认为 ConcurrentSkipListMap 赢得了比赛。