它是线程安全的。但是,线程安全的方式可能不是您所期望的。您可以从以下位置看到一些“提示”:
此类可与依赖于其线程安全性但不依赖于其同步详细信息的程序完全互操作Hashtable
要以更完整的画面了解整个故事,您需要了解界面。ConcurrentMap
原始文件提供了一些非常基本的读取/更新方法。甚至我能够使 ;有很多情况下,如果不考虑我的同步机制,人们就无法使用我的地图。这是一个典型的例子:Map
Map
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
这段代码不是线程安全的,即使映射本身是线程安全的。同时调用的两个线程可能会认为没有这样的密钥,因此它们都插入到 .containsKey()
Map
为了解决这个问题,我们需要显式地进行额外的同步。假设我的Map的线程安全性是通过同步关键字实现的,您将需要这样做:
synchronized(threadSafeMap) {
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
}
这种额外的代码需要您了解映射的“同步详细信息”。在上面的例子中,我们需要知道同步是通过“同步”实现的。
ConcurrentMap
接口更进一步。它定义了一些常见的“复杂”操作,这些操作涉及对地图的多次访问。例如,上面的示例公开为 。通过这些“复杂”操作,(在大多数情况下)的用户无需将操作与对地图的多个访问权限同步。因此,Map的实现可以执行更复杂的同步机制以获得更好的性能。 就是一个很好的例子。实际上,线程安全是通过为映射的不同分区保留单独的锁来维护的。它是线程安全的,因为对映射的并发访问不会破坏内部数据结构,也不会导致任何意外丢失更新等。putIfAbsent()
ConcurrentMap
ConcurrentHashhMap
考虑到上述所有情况,Javadoc的含义将更加清晰:
“检索操作(包括 get)通常不会阻塞”,因为没有使用“synchronized”作为其线程安全。逻辑本身负责线程安全;如果你在Javadoc中进一步看:ConcurrentHashMap
get
该表在内部分区,以尝试允许指定数量的并发更新而不会发生争用
检索不仅是非阻塞的,甚至更新也可以同时发生。但是,非阻塞/并发更新并不意味着它是线程 UNsafe。它只是意味着它正在使用一些方法,而不是简单的“同步”线程安全。
但是,由于内部同步机制未公开,因此,如果要执行 除 提供的操作之外的一些复杂操作,则可能需要考虑更改逻辑,或者考虑不使用 .例如:ConcurrentMap
ConcurrentHashMap
// only remove if both key1 and key2 exists
if (map.containsKey(key1) && map.containsKey(key2)) {
map.remove(key1);
map.remove(key2);
}