我需要一个多线程 Map 对象在我的 Web 服务器的缓存中使用,并且我需要有
null
键。
HashMap
允许我拥有空键,但 ConcurrentHashMap
不允许。我尝试使用 HashMap
创建 Collections.synchronizedMap(new HashMap())
的同步版本,但它也不接受 null
键。
我可以使用任何替代方法,而不必实施某种方法来包装
null
键吗?
Map
返回的
Collections.synchronizedMap
支持您提供的Map
的所有功能。如果你给它一个 HashMap
,它支持 null
键(还有 null
值,你说 “...我需要有“空”键值...” 可以读取方式)。
这按预期工作,例如:
import java.util.*;
public class MapTest
{
public static final void main(String[] args)
{
Map map;
try
{
map = Collections.synchronizedMap(new HashMap());
map.put("one", "a");
System.out.println("Size = " + map.size());
map.put(null, "b");
System.out.println("Size = " + map.size());
System.out.println("map.get(null) = " + map.get(null));
}
catch (Exception ex)
{
System.out.println("Exception: " + ex.getMessage());
ex.printStackTrace(System.out);
}
System.exit(0);
}
}
输出:
尺寸 = 1 尺寸 = 2 地图.get(null) = b
同步地图有一个问题,那就是它是同步的。如果您可以解决对
null
键和值的需求,那么 ConcurrentHashMap
可能是服务器缓存的更好选择。但它“...不允许null
用作键或值。”
请注意,如果要迭代,则需要从
synchronizedMap
手动同步地图。来自JavaDoc:
当用户通过 Iterator、Spliterator 或 Stream 遍历任何集合视图时,必须在返回的映射上手动同步:
...
不遵循此建议可能会导致不确定的行为。
地图会在
get
等方面为您处理它,但不会迭代。
据我所知,既没有简单的方法来制作
ConcurrentHashMap
,也没有支持 null
键或值的等效类。
ConcurrentHashMap
与 Collections.synchronizedMap(new HashMap())
有很大不同。
首先,因为同步映射将阻止任何并发访问同时发生,即使所有访问都是只读的。
ConcurrentHashMap
不会阻止并发读取访问,在某些情况下甚至可能接受并发写入。
但更重要的是,如果在使用迭代器时修改了底层映射,则同步映射返回的
Iterator
很容易抛出ConcurrentModificationException
。另一方面,即使在使用迭代器时更改了底层映射,ConcurrentHashMap
迭代器也保证永远不会抛出ConcurrentModificationException
。