具有空键功能的线程安全映射

问题描述 投票:0回答:2

我需要一个多线程 Map 对象在我的 Web 服务器的缓存中使用,并且我需要有

null
键。

HashMap
允许我拥有空键,但
ConcurrentHashMap
不允许。我尝试使用
HashMap
创建
Collections.synchronizedMap(new HashMap())
的同步版本,但它也不接受
null
键。

我可以使用任何替代方法,而不必实施某种方法来包装

null
键吗?

java synchronization hashmap concurrenthashmap
2个回答
8
投票

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
等方面为您处理它,但不会迭代。


4
投票

据我所知,既没有简单的方法来制作

ConcurrentHashMap
,也没有支持
null
键或值的等效类。

ConcurrentHashMap
Collections.synchronizedMap(new HashMap())
有很大不同。

首先,因为同步映射将阻止任何并发访问同时发生,即使所有访问都是只读的。

ConcurrentHashMap
不会阻止并发读取访问,在某些情况下甚至可能接受并发写入。

但更重要的是,如果在使用迭代器时修改了底层映射,则同步映射返回的

Iterator
很容易抛出
ConcurrentModificationException
。另一方面,即使在使用迭代器时更改了底层映射,
ConcurrentHashMap
迭代器也保证永远不会抛出
ConcurrentModificationException

© www.soinside.com 2019 - 2024. All rights reserved.