ConcurrentHashMap和collection . synchronizedmap (Map)有什么区别?

时间:2021-10-06 15:50:19

I have a Map which is to be modified by several threads concurrently.

我有一个映射,它将被几个线程同时修改。

There seem to be three different synchronized Map implementations in the Java API:

在Java API中似乎有三种不同的同步映射实现:

  • Hashtable
  • 哈希表
  • Collections.synchronizedMap(Map)
  • collections . synchronizedmap(地图)
  • ConcurrentHashMap
  • ConcurrentHashMap

From what I understand, Hashtable is an old implementation (extending the obsolete Dictionary class), which has been adapted later to fit the Map interface. While it is synchronized, it seems to have serious scalability issues and is discouraged for new projects.

根据我的理解,Hashtable是一个旧的实现(扩展了过时的Dictionary类),稍后将其修改为适合Map接口。虽然它是同步的,但是它似乎有严重的可伸缩性问题,并且不鼓励新项目。

But what about the other two? What are the differences between Maps returned by Collections.synchronizedMap(Map) and ConcurrentHashMaps? Which one fits which situation?

但是另外两个呢?由collection . synchronizedmap (Map)地图和ConcurrentHashMaps返回的地图有什么区别?哪一个适合哪一种情况?

18 个解决方案

#1


366  

For your needs, use ConcurrentHashMap. It allows concurrent modification of the Map from several threads without the need to block them. Collections.synchronizedMap(map) creates a blocking Map which will degrade performance, albeit ensure consistency (if used properly).

根据您的需要,请使用ConcurrentHashMap。它允许从几个线程并发修改映射,而不需要阻塞它们。synchronizedmap (map)创建了一个阻塞映射,它将降低性能,但确保一致性(如果使用得当)。

Use the second option if you need to ensure data consistency, and each thread needs to have an up-to-date view of the map. Use the first if performance is critical, and each thread only inserts data to the map, with reads happening less frequently.

如果需要确保数据一致性,并且每个线程都需要有映射的最新视图,请使用第二个选项。如果性能是关键的,请使用第一个,并且每个线程只向映射插入数据,读取的频率更低。

#2


197  

╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║Is thread-safe ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Regarding locking mechanism: Hashtable locks the object, while ConcurrentHashMap locks only the bucket.

关于锁定机制:Hashtable锁定对象,而ConcurrentHashMap只锁定bucket。

#3


126  

The "scalability issues" for Hashtable are present in exactly the same way in Collections.synchronizedMap(Map) - they use very simple synchronization, which means that only one thread can access the map at the same time.

Hashtable的“可伸缩性问题”在collection . synchronizedmap (Map)中以完全相同的方式出现——它们使用非常简单的同步,这意味着只有一个线程可以同时访问映射。

This is not much of an issue when you have simple inserts and lookups (unless you do it extremely intensively), but becomes a big problem when you need to iterate over the entire Map, which can take a long time for a large Map - while one thread does that, all others have to wait if they want to insert or lookup anything.

这不是太大的问题,当你有简单的插入和查找(除非你极其密集),但是当你成为一个大问题需要遍历整个地图,这可能需要很长时间的大地图,而一个线程,所有其他需要等待如果他们想插入或查找任何东西。

The ConcurrentHashMap uses very sophisticated techniques to reduce the need for synchronization and allow parallel read access by multiple threads without synchronization and, more importantly, provides an Iterator that requires no synchronization and even allows the Map to be modified during interation (though it makes no guarantees whether or not elements that were inserted during iteration will be returned).

ConcurrentHashMap使用非常复杂的技术来减少由多个线程同步和允许并行读访问没有同步和,更重要的是,提供了一个迭代器,不需要同步,甚至允许修改地图在交互影响(尽管它不保证是否插入的元素在迭代将返回)。

#4


31  

ConcurrentHashMap is preferred when you can use it - though it requires at least Java 5.

当您可以使用ConcurrentHashMap时,首选是ConcurrentHashMap—尽管它至少需要Java 5。

It is designed to scale well when used by multiple threads. Performance may be marginally poorer when only a single thread accesses the Map at a time, but significantly better when multiple threads access the map concurrently.

当被多个线程使用时,它被设计成可以很好地伸缩。当单个线程一次访问Map时,性能可能会稍微差一些,但是当多个线程同时访问Map时,性能会显著提高。

I found a blog entry that reproduces a table from the excellent book Java Concurrency In Practice, which I thoroughly recommend.

我发现了一个博客条目,它从优秀的《Java并发实践》中复制了一个表,我强烈推荐这个条目。

Collections.synchronizedMap makes sense really only if you need to wrap up a map with some other characteristics, perhaps some sort of ordered map, like a TreeMap.

集合。同步映射只有在需要将具有其他一些特征的映射打包时才有意义,可能是某种有序映射,比如TreeMap。

#5


28  

The main difference between these two is that ConcurrentHashMap will lock only portion of the data which are being updated while other portion of data can be accessed by other threads. However, Collections.synchronizedMap() will lock all the data while updating, other threads can only access the data when the lock is released. If there are many update operations and relative small amount of read operations, you should choose ConcurrentHashMap.

两者之间的主要区别在于,ConcurrentHashMap只锁定正在更新的数据的一部分,而其他线程可以访问其他部分的数据。但是,Collections.synchronizedMap()将在更新时锁定所有数据,其他线程只能在释放锁时访问数据。如果有许多更新操作和相对少量的读操作,您应该选择ConcurrentHashMap。

Also one other difference is that ConcurrentHashMap will not preserve the order of elements in the Map passed in. It is similar to HashMap when storing data. There is no guarantee that the element order is preserved. While Collections.synchronizedMap() will preserve the elements order of the Map passed in. For example, if you pass a TreeMap to ConcurrentHashMap, the elements order in the ConcurrentHashMap may not be the same as the order in the TreeMap, but Collections.synchronizedMap() will preserve the order.

另一个不同之处在于,ConcurrentHashMap不会保留传入的映射中的元素的顺序。它在存储数据时类似于HashMap。不能保证元素顺序被保留。而Collections.synchronizedMap()将保留传入的Map的元素顺序。例如,如果您传递一个TreeMap到ConcurrentHashMap,那么ConcurrentHashMap中的元素顺序可能与TreeMap中的顺序不同,但是Collections.synchronizedMap()将保留这个顺序。

Furthermore, ConcurrentHashMap can guarantee that there is no ConcurrentModificationException thrown while one thread is updating the map and another thread is traversing the iterator obtained from the map. However, Collections.synchronizedMap() is not guaranteed on this.

此外,ConcurrentHashMap可以保证在一个线程更新映射和另一个线程遍历从映射获得的迭代器时不会抛出ConcurrentModificationException。但是,collection . synchronizedmap()并不是在这里得到保证。

There is one post which demonstrate the differences of these two and also the ConcurrentSkipListMap.

有一篇文章展示了两者的不同之处,也展示了ConcurrentSkipListMap。

#6


12  

In ConcurrentHashMap, the lock is applied to a segment instead of an entire Map. Each segment manages its own internal hash table. The lock is applied only for update operations. Collections.synchronizedMap(Map) synchronizes the entire map.

在ConcurrentHashMap中,锁被应用于一个段,而不是整个映射。每个段管理自己的内部哈希表。锁只应用于更新操作。集合。同步映射(Map)同步整个映射。

#7


11  

  • Hashtable and ConcurrentHashMap do not allow null keys or null values.

    Hashtable和ConcurrentHashMap不允许使用空键或空值。

  • Collections.synchronizedMap(Map) synchronizes all operations (get, put, size, etc).

    同步映射(Map)同步所有操作(get、put、size等)。

  • ConcurrentHashMap supports full concurrency of retrievals, and adjustable expected concurrency for updates.

    ConcurrentHashMap支持检索的完全并发性,以及可调的更新预期并发性。

As usual, there are concurrency--overhead--speed tradeoffs involved. You really need to consider the detailed concurrency requirements of your application to make a decision, and then test your code to see if it's good enough.

与往常一样,涉及到并发——开销——速度的权衡。您确实需要考虑应用程序的详细并发性需求来作出决定,然后测试代码,看看是否足够好。

#8


9  

You are right about HashTable, you can forget about it.

您对HashTable的看法是对的,您可以忘记它。

Your article mentions the fact that while HashTable and the synchronized wrapper class provide basic thread-safety by only allowing one thread at a time to access the map, this is not 'true' thread-safety since many compound operations still require additional synchronization, for example:

您的文章提到,尽管HashTable和synchronized包装类每次只允许一个线程访问映射,从而提供了基本的线程安全,但这并不是真正的线程安全,因为许多复合操作仍然需要额外的同步,例如:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

However, don't think that ConcurrentHashMap is a simple alternative for a HashMap with a typical synchronized block as shown above. Read this article to understand its intricacies better.

但是,不要认为ConcurrentHashMap是一个具有典型的同步块的HashMap的简单替代,如上所示。阅读这篇文章可以更好地理解它的复杂性。

#9


7  

Here are few :

这里有几个:

1) ConcurrentHashMap locks only portion of Map but SynchronizedMap locks whole MAp.
2) ConcurrentHashMap has better performance over SynchronizedMap and more scalable.
3) In case of multiple reader and Single writer ConcurrentHashMap is best choice.

1) ConcurrentHashMap只锁定Map的一部分,而同步Map锁定整个Map。2)与同步映射相比,ConcurrentHashMap具有更好的性能和更强的可扩展性。3)如果有多名读者和一名作者同时使用,最好使用地图。

This text is from Difference between ConcurrentHashMap and hashtable in Java

此文本来自于Java中的ConcurrentHashMap和hashtable之间的差异

#10


7  

We can achieve thread safety by using ConcurrentHashMap and synchronisedHashmap and Hashtable. But there is a lot of difference if you look at their architecture.

我们可以使用ConcurrentHashMap和同步hashmap和Hashtable实现线程安全。但如果你看看他们的建筑结构,就会发现有很多不同之处。

  1. synchronisedHashmap and Hashtable
  2. synchronisedHashmap和哈希表

Both will maintain the lock at the object level. So if you want to perform any operation like put/get then you have to acquire the lock first. At the same time, other threads are not allowed to perform any operation. So at a time, only one thread can operate on this. So the waiting time will increase here. We can say that performance is relatively low when you comparing with ConcurrentHashMap.

两者都将在对象级别上维护锁。因此,如果你想执行任何操作,比如put/get,那么你必须先获得锁。同时,不允许其他线程执行任何操作。所以在这个时候,只有一个线程可以操作这个。所以这里的等待时间会增加。与ConcurrentHashMap相比,我们可以说性能相对较低。

  1. ConcurrentHashMap
  2. ConcurrentHashMap

It will maintain the lock at segment level. It has 16 segments and maintains the concurrency level as 16 by default. So at a time, 16 threads can be able to operate on ConcurrentHashMap. Moreover, read operation doesn't require a lock. So any number of threads can perform a get operation on it.

它将在段级维护锁。它有16个段,默认情况下将并发级别保持为16。因此,一次有16个线程可以对ConcurrentHashMap进行操作。此外,读操作不需要锁。所以任意数量的线程都可以对它执行get操作。

If thread1 wants to perform put operation in segment 2 and thread2 wants to perform put operation on segment 4 then it is allowed here. Means, 16 threads can perform update(put/delete) operation on ConcurrentHashMap at a time.

如果thread1想要在段2中执行put操作,而thread2想要在第4段执行put操作,那么这里就允许执行。意味着,16个线程可以一次对ConcurrentHashMap执行更新(put/delete)操作。

So that the waiting time will be less here. Hence the performance is relatively better than synchronisedHashmap and Hashtable.

这样等待的时间就会减少。因此,性能比synchronisedHashmap和Hashtable要好。

#11


5  

ConcurrentHashMap

ConcurrentHashMap

  • You should use ConcurrentHashMap when you need very high concurrency in your project.
  • 当您的项目需要非常高的并发性时,您应该使用ConcurrentHashMap。
  • It is thread safe without synchronizing the whole map.
  • 在不同步整个映射的情况下,它是线程安全的。
  • Reads can happen very fast while write is done with a lock.
  • 读操作可以非常快地发生,而写操作是用锁完成的。
  • There is no locking at the object level.
  • 在对象层没有锁。
  • The locking is at a much finer granularity at a hashmap bucket level.
  • 在hashmap bucket级别上,锁定的粒度要细得多。
  • ConcurrentHashMap doesn’t throw a ConcurrentModificationException if one thread tries to modify it while another is iterating over it.
  • ConcurrentHashMap不会抛出ConcurrentModificationException,如果一个线程试图在另一个线程迭代它时修改它。
  • ConcurrentHashMap uses multitude of locks.
  • ConcurrentHashMap使用大量的锁。

SynchronizedHashMap

SynchronizedHashMap

  • Synchronization at Object level.
  • 同步对象层次。
  • Every read/write operation needs to acquire lock.
  • 每次读写操作都需要获取锁。
  • Locking the entire collection is a performance overhead.
  • 锁定整个集合是一个性能开销。
  • This essentially gives access to only one thread to the entire map & blocks all the other threads.
  • 这实际上只允许一个线程访问整个映射,并阻塞所有其他线程。
  • It may cause contention.
  • 它可能会引起争论。
  • SynchronizedHashMap returns Iterator, which fails-fast on concurrent modification.
  • SynchronizedHashMap返回迭代器,它可以在并发修改上快速失败。

source

#12


4  

ConcurrentHashMap is optimized for concurrent access.

ConcurrentHashMap是为并发访问而优化的。

Accesses don't lock the whole map but use a finer grained strategy, which improves scalability. There are also functional enhanvements specifically for concurrent access, e.g. concurrent iterators.

访问不会锁定整个映射,而是使用更细粒度的策略,这可以提高可伸缩性。还有一些特定于并发访问的功能增强,例如并发迭代器。

#13


2  

There is one critical feature to note about ConcurrentHashMap other than concurrency feature it provides, which is fail-safe iterator. I have seen developers using ConcurrentHashMap just because they want to edit the entryset - put/remove while iterating over it. Collections.synchronizedMap(Map) does not provide fail-safe iterator but it provides fail-fast iterator instead. fail-fast iterators uses snapshot of the size of map which can not be edited during iteration.

对于ConcurrentHashMap,除了它提供的并发特性(即故障安全迭代器)之外,还有一个关键特性需要注意。我看到开发人员使用ConcurrentHashMap仅仅是因为他们希望在迭代时编辑entryset - put/remove。synchronizedmap (Map)没有提供故障安全迭代器,但是它提供了故障快速迭代器。快速故障迭代器使用映射大小的快照,在迭代期间不能对其进行编辑。

#14


2  

  1. If Data Consistency is highly important - Use Hashtable or Collections.synchronizedMap(Map).
  2. 如果数据一致性非常重要——使用Hashtable或collection . synchronizedmap (Map)。
  3. If speed/performance is highly important and Data Updating can be compromised- Use ConcurrentHashMap.
  4. 如果速度/性能非常重要,数据更新可能会受到影响——使用ConcurrentHashMap。

#15


2  

Synchronized Map:

同步地图:

Synchronized Map is also not very different than Hashtable and provides similar performance in concurrent Java programs. Only difference between Hashtable and SynchronizedMap is that SynchronizedMap is not a legacy and you can wrap any Map to create it’s synchronized version by using Collections.synchronizedMap() method.

同步映射也与Hashtable不同,并在并发Java程序中提供了类似的性能。Hashtable和SynchronizedMap之间唯一的区别是同步映射不是遗留的,您可以使用Collections.synchronizedMap()方法包装任何映射来创建它的同步版本。

ConcurrentHashMap:

ConcurrentHashMap:

The ConcurrentHashMap class provides a concurrent version of the standard HashMap. This is an improvement on the synchronizedMap functionality provided in the Collections class.

ConcurrentHashMap类提供了标准HashMap的并发版本。这是对Collections类中提供的同步映射功能的改进。

Unlike Hashtable and Synchronized Map, it never locks whole Map, instead it divides the map in segments and locking is done on those. It perform better if number of reader threads are greater than number of writer threads.

与Hashtable和Synchronized Map不同的是,它从不锁整个Map,而是将Map划分成分段,并在这些分段上进行锁定。如果读线程的数量大于写线程的数量,则执行得更好。

ConcurrentHashMap by default is separated into 16 regions and locks are applied. This default number can be set while initializing a ConcurrentHashMap instance. When setting data in a particular segment, the lock for that segment is obtained. This means that two updates can still simultaneously execute safely if they each affect separate buckets, thus minimizing lock contention and so maximizing performance.

默认情况下,ConcurrentHashMap被分成16个区域,并应用锁。在初始化ConcurrentHashMap实例时,可以设置这个默认数字。当在特定段中设置数据时,将获得该段的锁。这意味着如果两个更新同时影响到不同的存储段,那么它们仍然可以安全地执行,从而最小化锁争用,从而最大化性能。

ConcurrentHashMap doesn’t throw a ConcurrentModificationException

ConcurrentHashMap不会抛出ConcurrentModificationException

ConcurrentHashMap doesn’t throw a ConcurrentModificationException if one thread tries to modify it while another is iterating over it

ConcurrentHashMap不会抛出ConcurrentModificationException,如果一个线程试图在另一个线程迭代它时修改它

Difference between synchornizedMap and ConcurrentHashMap

同步地图和并发地图的区别

Collections.synchornizedMap(HashMap) will return a collection which is almost equivalent to Hashtable, where every modification operation on Map is locked on Map object while in case of ConcurrentHashMap, thread-safety is achieved by dividing whole Map into different partition based upon concurrency level and only locking particular portion instead of locking whole Map.

Collections.synchornizedMap(HashMap)将返回一个收集几乎相当于散列表,地图被锁定在地图上,每个修改操作对象在ConcurrentHashMap的情况下,线程安全是通过整个地图划分成不同的分区基于并发级别只有锁定特定的部分而不是锁定整个地图。

ConcurrentHashMap does not allow null keys or null values while synchronized HashMap allows one null keys.

ConcurrentHashMap不允许空键或空值,而synchronized HashMap允许一个空键。

Similar links

类似的链接

Link1

Link1

Link2

Link2

Performance Comparison

性能比较

#16


1  

Collections.synchronizedMap() method synchronizes all the methods of the HashMap and effectively reduces it to a data structure where one thread can enter at a time because it locks every method on a common lock.

synchronizedmap()方法同步散星图的所有方法,并且有效地将散星图简化为一个数据结构,在这个数据结构中,一个线程可以一次输入,因为它将每个方法锁在一个公共锁上。

In ConcurrentHashMap synchronization is done a little differently. Rather than locking every method on a common lock, ConcurrentHashMap uses separate lock for separate buckets thus locking only a portion of the Map. By default there are 16 buckets and also separate locks for separate buckets. So the default concurrency level is 16. That means theoretically any given time 16 threads can access ConcurrentHashMap if they all are going to separate buckets.

在ConcurrentHashMap中,同步处理方式略有不同。ConcurrentHashMap并不是将每个方法锁定在一个普通的锁上,而是使用单独的锁来分离bucket,从而只锁定了地图的一部分。默认情况下,有16个桶,还有单独的锁用于单独的桶。所以默认的并发级别是16。这意味着理论上任何给定的时间,如果16个线程都要分离bucket,它们都可以访问ConcurrentHashMap。

#17


0  

In general, if you want to use the ConcurrentHashMap make sure you are ready to miss 'updates'
(i.e. printing contents of the HashMap does not ensure it will print the up-to-date Map) and use APIs like CyclicBarrier to ensure consistency across your program's lifecycle.

一般来说,如果您想使用ConcurrentHashMap,请确保您已经准备好错过“更新”(例如,打印HashMap的内容并不保证它会打印最新的Map),并使用循环屏障等api来确保程序生命周期的一致性。

#18


0  

Besides what has been suggested, I'd like to post the source code related to SynchronizedMap.

除了建议之外,我还想发布与SynchronizedMap相关的源代码。

To make a Map thread safe, we can use Collections.synchronizedMap statement and input the map instance as the parameter.

为了使地图线程安全,我们可以使用集合。同步映射语句并将映射实例作为参数输入。

The implementation of synchronizedMap in Collections is like below

在集合中同步映射的实现如下所示

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

As you can see, the input Map object is wrapped by the SynchronizedMap object.
Let's dig into the implementation of SynchronizedMap ,

如您所见,输入映射对象由SynchronizedMap对象包装。让我们深入了解同步映射的实现,

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

What SynchronizedMap does can be summarized as adding a single lock to primary method of the input Map object. All method guarded by the lock can't be accessed by multiple threads at the same time. That means normal operations like put and get can be executed by a single thread at the same time for all data in the Map object.

同步映射的作用可以概括为向输入映射对象的主方法添加一个锁。由锁保护的所有方法不能同时被多个线程访问。这意味着,对于Map对象中的所有数据,像put和get这样的普通操作可以由一个线程同时执行。

It makes the Map object thread safe now but the performance may become an issue in some scenarios.

它使Map对象线程现在是安全的,但是性能在某些场景中可能会成为问题。

The ConcurrentMap is far more complicated in the implementation, we can refer to Building a better HashMap for details. In a nutshell, it's implemented taking both thread safe and performance into consideration.

在实现中,ConcurrentMap要复杂得多,我们可以参考构建一个更好的HashMap以获得详细信息。简而言之,它是在考虑线程安全性和性能的情况下实现的。

#1


366  

For your needs, use ConcurrentHashMap. It allows concurrent modification of the Map from several threads without the need to block them. Collections.synchronizedMap(map) creates a blocking Map which will degrade performance, albeit ensure consistency (if used properly).

根据您的需要,请使用ConcurrentHashMap。它允许从几个线程并发修改映射,而不需要阻塞它们。synchronizedmap (map)创建了一个阻塞映射,它将降低性能,但确保一致性(如果使用得当)。

Use the second option if you need to ensure data consistency, and each thread needs to have an up-to-date view of the map. Use the first if performance is critical, and each thread only inserts data to the map, with reads happening less frequently.

如果需要确保数据一致性,并且每个线程都需要有映射的最新视图,请使用第二个选项。如果性能是关键的,请使用第一个,并且每个线程只向映射插入数据,读取的频率更低。

#2


197  

╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║Is thread-safe ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Regarding locking mechanism: Hashtable locks the object, while ConcurrentHashMap locks only the bucket.

关于锁定机制:Hashtable锁定对象,而ConcurrentHashMap只锁定bucket。

#3


126  

The "scalability issues" for Hashtable are present in exactly the same way in Collections.synchronizedMap(Map) - they use very simple synchronization, which means that only one thread can access the map at the same time.

Hashtable的“可伸缩性问题”在collection . synchronizedmap (Map)中以完全相同的方式出现——它们使用非常简单的同步,这意味着只有一个线程可以同时访问映射。

This is not much of an issue when you have simple inserts and lookups (unless you do it extremely intensively), but becomes a big problem when you need to iterate over the entire Map, which can take a long time for a large Map - while one thread does that, all others have to wait if they want to insert or lookup anything.

这不是太大的问题,当你有简单的插入和查找(除非你极其密集),但是当你成为一个大问题需要遍历整个地图,这可能需要很长时间的大地图,而一个线程,所有其他需要等待如果他们想插入或查找任何东西。

The ConcurrentHashMap uses very sophisticated techniques to reduce the need for synchronization and allow parallel read access by multiple threads without synchronization and, more importantly, provides an Iterator that requires no synchronization and even allows the Map to be modified during interation (though it makes no guarantees whether or not elements that were inserted during iteration will be returned).

ConcurrentHashMap使用非常复杂的技术来减少由多个线程同步和允许并行读访问没有同步和,更重要的是,提供了一个迭代器,不需要同步,甚至允许修改地图在交互影响(尽管它不保证是否插入的元素在迭代将返回)。

#4


31  

ConcurrentHashMap is preferred when you can use it - though it requires at least Java 5.

当您可以使用ConcurrentHashMap时,首选是ConcurrentHashMap—尽管它至少需要Java 5。

It is designed to scale well when used by multiple threads. Performance may be marginally poorer when only a single thread accesses the Map at a time, but significantly better when multiple threads access the map concurrently.

当被多个线程使用时,它被设计成可以很好地伸缩。当单个线程一次访问Map时,性能可能会稍微差一些,但是当多个线程同时访问Map时,性能会显著提高。

I found a blog entry that reproduces a table from the excellent book Java Concurrency In Practice, which I thoroughly recommend.

我发现了一个博客条目,它从优秀的《Java并发实践》中复制了一个表,我强烈推荐这个条目。

Collections.synchronizedMap makes sense really only if you need to wrap up a map with some other characteristics, perhaps some sort of ordered map, like a TreeMap.

集合。同步映射只有在需要将具有其他一些特征的映射打包时才有意义,可能是某种有序映射,比如TreeMap。

#5


28  

The main difference between these two is that ConcurrentHashMap will lock only portion of the data which are being updated while other portion of data can be accessed by other threads. However, Collections.synchronizedMap() will lock all the data while updating, other threads can only access the data when the lock is released. If there are many update operations and relative small amount of read operations, you should choose ConcurrentHashMap.

两者之间的主要区别在于,ConcurrentHashMap只锁定正在更新的数据的一部分,而其他线程可以访问其他部分的数据。但是,Collections.synchronizedMap()将在更新时锁定所有数据,其他线程只能在释放锁时访问数据。如果有许多更新操作和相对少量的读操作,您应该选择ConcurrentHashMap。

Also one other difference is that ConcurrentHashMap will not preserve the order of elements in the Map passed in. It is similar to HashMap when storing data. There is no guarantee that the element order is preserved. While Collections.synchronizedMap() will preserve the elements order of the Map passed in. For example, if you pass a TreeMap to ConcurrentHashMap, the elements order in the ConcurrentHashMap may not be the same as the order in the TreeMap, but Collections.synchronizedMap() will preserve the order.

另一个不同之处在于,ConcurrentHashMap不会保留传入的映射中的元素的顺序。它在存储数据时类似于HashMap。不能保证元素顺序被保留。而Collections.synchronizedMap()将保留传入的Map的元素顺序。例如,如果您传递一个TreeMap到ConcurrentHashMap,那么ConcurrentHashMap中的元素顺序可能与TreeMap中的顺序不同,但是Collections.synchronizedMap()将保留这个顺序。

Furthermore, ConcurrentHashMap can guarantee that there is no ConcurrentModificationException thrown while one thread is updating the map and another thread is traversing the iterator obtained from the map. However, Collections.synchronizedMap() is not guaranteed on this.

此外,ConcurrentHashMap可以保证在一个线程更新映射和另一个线程遍历从映射获得的迭代器时不会抛出ConcurrentModificationException。但是,collection . synchronizedmap()并不是在这里得到保证。

There is one post which demonstrate the differences of these two and also the ConcurrentSkipListMap.

有一篇文章展示了两者的不同之处,也展示了ConcurrentSkipListMap。

#6


12  

In ConcurrentHashMap, the lock is applied to a segment instead of an entire Map. Each segment manages its own internal hash table. The lock is applied only for update operations. Collections.synchronizedMap(Map) synchronizes the entire map.

在ConcurrentHashMap中,锁被应用于一个段,而不是整个映射。每个段管理自己的内部哈希表。锁只应用于更新操作。集合。同步映射(Map)同步整个映射。

#7


11  

  • Hashtable and ConcurrentHashMap do not allow null keys or null values.

    Hashtable和ConcurrentHashMap不允许使用空键或空值。

  • Collections.synchronizedMap(Map) synchronizes all operations (get, put, size, etc).

    同步映射(Map)同步所有操作(get、put、size等)。

  • ConcurrentHashMap supports full concurrency of retrievals, and adjustable expected concurrency for updates.

    ConcurrentHashMap支持检索的完全并发性,以及可调的更新预期并发性。

As usual, there are concurrency--overhead--speed tradeoffs involved. You really need to consider the detailed concurrency requirements of your application to make a decision, and then test your code to see if it's good enough.

与往常一样,涉及到并发——开销——速度的权衡。您确实需要考虑应用程序的详细并发性需求来作出决定,然后测试代码,看看是否足够好。

#8


9  

You are right about HashTable, you can forget about it.

您对HashTable的看法是对的,您可以忘记它。

Your article mentions the fact that while HashTable and the synchronized wrapper class provide basic thread-safety by only allowing one thread at a time to access the map, this is not 'true' thread-safety since many compound operations still require additional synchronization, for example:

您的文章提到,尽管HashTable和synchronized包装类每次只允许一个线程访问映射,从而提供了基本的线程安全,但这并不是真正的线程安全,因为许多复合操作仍然需要额外的同步,例如:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

However, don't think that ConcurrentHashMap is a simple alternative for a HashMap with a typical synchronized block as shown above. Read this article to understand its intricacies better.

但是,不要认为ConcurrentHashMap是一个具有典型的同步块的HashMap的简单替代,如上所示。阅读这篇文章可以更好地理解它的复杂性。

#9


7  

Here are few :

这里有几个:

1) ConcurrentHashMap locks only portion of Map but SynchronizedMap locks whole MAp.
2) ConcurrentHashMap has better performance over SynchronizedMap and more scalable.
3) In case of multiple reader and Single writer ConcurrentHashMap is best choice.

1) ConcurrentHashMap只锁定Map的一部分,而同步Map锁定整个Map。2)与同步映射相比,ConcurrentHashMap具有更好的性能和更强的可扩展性。3)如果有多名读者和一名作者同时使用,最好使用地图。

This text is from Difference between ConcurrentHashMap and hashtable in Java

此文本来自于Java中的ConcurrentHashMap和hashtable之间的差异

#10


7  

We can achieve thread safety by using ConcurrentHashMap and synchronisedHashmap and Hashtable. But there is a lot of difference if you look at their architecture.

我们可以使用ConcurrentHashMap和同步hashmap和Hashtable实现线程安全。但如果你看看他们的建筑结构,就会发现有很多不同之处。

  1. synchronisedHashmap and Hashtable
  2. synchronisedHashmap和哈希表

Both will maintain the lock at the object level. So if you want to perform any operation like put/get then you have to acquire the lock first. At the same time, other threads are not allowed to perform any operation. So at a time, only one thread can operate on this. So the waiting time will increase here. We can say that performance is relatively low when you comparing with ConcurrentHashMap.

两者都将在对象级别上维护锁。因此,如果你想执行任何操作,比如put/get,那么你必须先获得锁。同时,不允许其他线程执行任何操作。所以在这个时候,只有一个线程可以操作这个。所以这里的等待时间会增加。与ConcurrentHashMap相比,我们可以说性能相对较低。

  1. ConcurrentHashMap
  2. ConcurrentHashMap

It will maintain the lock at segment level. It has 16 segments and maintains the concurrency level as 16 by default. So at a time, 16 threads can be able to operate on ConcurrentHashMap. Moreover, read operation doesn't require a lock. So any number of threads can perform a get operation on it.

它将在段级维护锁。它有16个段,默认情况下将并发级别保持为16。因此,一次有16个线程可以对ConcurrentHashMap进行操作。此外,读操作不需要锁。所以任意数量的线程都可以对它执行get操作。

If thread1 wants to perform put operation in segment 2 and thread2 wants to perform put operation on segment 4 then it is allowed here. Means, 16 threads can perform update(put/delete) operation on ConcurrentHashMap at a time.

如果thread1想要在段2中执行put操作,而thread2想要在第4段执行put操作,那么这里就允许执行。意味着,16个线程可以一次对ConcurrentHashMap执行更新(put/delete)操作。

So that the waiting time will be less here. Hence the performance is relatively better than synchronisedHashmap and Hashtable.

这样等待的时间就会减少。因此,性能比synchronisedHashmap和Hashtable要好。

#11


5  

ConcurrentHashMap

ConcurrentHashMap

  • You should use ConcurrentHashMap when you need very high concurrency in your project.
  • 当您的项目需要非常高的并发性时,您应该使用ConcurrentHashMap。
  • It is thread safe without synchronizing the whole map.
  • 在不同步整个映射的情况下,它是线程安全的。
  • Reads can happen very fast while write is done with a lock.
  • 读操作可以非常快地发生,而写操作是用锁完成的。
  • There is no locking at the object level.
  • 在对象层没有锁。
  • The locking is at a much finer granularity at a hashmap bucket level.
  • 在hashmap bucket级别上,锁定的粒度要细得多。
  • ConcurrentHashMap doesn’t throw a ConcurrentModificationException if one thread tries to modify it while another is iterating over it.
  • ConcurrentHashMap不会抛出ConcurrentModificationException,如果一个线程试图在另一个线程迭代它时修改它。
  • ConcurrentHashMap uses multitude of locks.
  • ConcurrentHashMap使用大量的锁。

SynchronizedHashMap

SynchronizedHashMap

  • Synchronization at Object level.
  • 同步对象层次。
  • Every read/write operation needs to acquire lock.
  • 每次读写操作都需要获取锁。
  • Locking the entire collection is a performance overhead.
  • 锁定整个集合是一个性能开销。
  • This essentially gives access to only one thread to the entire map & blocks all the other threads.
  • 这实际上只允许一个线程访问整个映射,并阻塞所有其他线程。
  • It may cause contention.
  • 它可能会引起争论。
  • SynchronizedHashMap returns Iterator, which fails-fast on concurrent modification.
  • SynchronizedHashMap返回迭代器,它可以在并发修改上快速失败。

source

#12


4  

ConcurrentHashMap is optimized for concurrent access.

ConcurrentHashMap是为并发访问而优化的。

Accesses don't lock the whole map but use a finer grained strategy, which improves scalability. There are also functional enhanvements specifically for concurrent access, e.g. concurrent iterators.

访问不会锁定整个映射,而是使用更细粒度的策略,这可以提高可伸缩性。还有一些特定于并发访问的功能增强,例如并发迭代器。

#13


2  

There is one critical feature to note about ConcurrentHashMap other than concurrency feature it provides, which is fail-safe iterator. I have seen developers using ConcurrentHashMap just because they want to edit the entryset - put/remove while iterating over it. Collections.synchronizedMap(Map) does not provide fail-safe iterator but it provides fail-fast iterator instead. fail-fast iterators uses snapshot of the size of map which can not be edited during iteration.

对于ConcurrentHashMap,除了它提供的并发特性(即故障安全迭代器)之外,还有一个关键特性需要注意。我看到开发人员使用ConcurrentHashMap仅仅是因为他们希望在迭代时编辑entryset - put/remove。synchronizedmap (Map)没有提供故障安全迭代器,但是它提供了故障快速迭代器。快速故障迭代器使用映射大小的快照,在迭代期间不能对其进行编辑。

#14


2  

  1. If Data Consistency is highly important - Use Hashtable or Collections.synchronizedMap(Map).
  2. 如果数据一致性非常重要——使用Hashtable或collection . synchronizedmap (Map)。
  3. If speed/performance is highly important and Data Updating can be compromised- Use ConcurrentHashMap.
  4. 如果速度/性能非常重要,数据更新可能会受到影响——使用ConcurrentHashMap。

#15


2  

Synchronized Map:

同步地图:

Synchronized Map is also not very different than Hashtable and provides similar performance in concurrent Java programs. Only difference between Hashtable and SynchronizedMap is that SynchronizedMap is not a legacy and you can wrap any Map to create it’s synchronized version by using Collections.synchronizedMap() method.

同步映射也与Hashtable不同,并在并发Java程序中提供了类似的性能。Hashtable和SynchronizedMap之间唯一的区别是同步映射不是遗留的,您可以使用Collections.synchronizedMap()方法包装任何映射来创建它的同步版本。

ConcurrentHashMap:

ConcurrentHashMap:

The ConcurrentHashMap class provides a concurrent version of the standard HashMap. This is an improvement on the synchronizedMap functionality provided in the Collections class.

ConcurrentHashMap类提供了标准HashMap的并发版本。这是对Collections类中提供的同步映射功能的改进。

Unlike Hashtable and Synchronized Map, it never locks whole Map, instead it divides the map in segments and locking is done on those. It perform better if number of reader threads are greater than number of writer threads.

与Hashtable和Synchronized Map不同的是,它从不锁整个Map,而是将Map划分成分段,并在这些分段上进行锁定。如果读线程的数量大于写线程的数量,则执行得更好。

ConcurrentHashMap by default is separated into 16 regions and locks are applied. This default number can be set while initializing a ConcurrentHashMap instance. When setting data in a particular segment, the lock for that segment is obtained. This means that two updates can still simultaneously execute safely if they each affect separate buckets, thus minimizing lock contention and so maximizing performance.

默认情况下,ConcurrentHashMap被分成16个区域,并应用锁。在初始化ConcurrentHashMap实例时,可以设置这个默认数字。当在特定段中设置数据时,将获得该段的锁。这意味着如果两个更新同时影响到不同的存储段,那么它们仍然可以安全地执行,从而最小化锁争用,从而最大化性能。

ConcurrentHashMap doesn’t throw a ConcurrentModificationException

ConcurrentHashMap不会抛出ConcurrentModificationException

ConcurrentHashMap doesn’t throw a ConcurrentModificationException if one thread tries to modify it while another is iterating over it

ConcurrentHashMap不会抛出ConcurrentModificationException,如果一个线程试图在另一个线程迭代它时修改它

Difference between synchornizedMap and ConcurrentHashMap

同步地图和并发地图的区别

Collections.synchornizedMap(HashMap) will return a collection which is almost equivalent to Hashtable, where every modification operation on Map is locked on Map object while in case of ConcurrentHashMap, thread-safety is achieved by dividing whole Map into different partition based upon concurrency level and only locking particular portion instead of locking whole Map.

Collections.synchornizedMap(HashMap)将返回一个收集几乎相当于散列表,地图被锁定在地图上,每个修改操作对象在ConcurrentHashMap的情况下,线程安全是通过整个地图划分成不同的分区基于并发级别只有锁定特定的部分而不是锁定整个地图。

ConcurrentHashMap does not allow null keys or null values while synchronized HashMap allows one null keys.

ConcurrentHashMap不允许空键或空值,而synchronized HashMap允许一个空键。

Similar links

类似的链接

Link1

Link1

Link2

Link2

Performance Comparison

性能比较

#16


1  

Collections.synchronizedMap() method synchronizes all the methods of the HashMap and effectively reduces it to a data structure where one thread can enter at a time because it locks every method on a common lock.

synchronizedmap()方法同步散星图的所有方法,并且有效地将散星图简化为一个数据结构,在这个数据结构中,一个线程可以一次输入,因为它将每个方法锁在一个公共锁上。

In ConcurrentHashMap synchronization is done a little differently. Rather than locking every method on a common lock, ConcurrentHashMap uses separate lock for separate buckets thus locking only a portion of the Map. By default there are 16 buckets and also separate locks for separate buckets. So the default concurrency level is 16. That means theoretically any given time 16 threads can access ConcurrentHashMap if they all are going to separate buckets.

在ConcurrentHashMap中,同步处理方式略有不同。ConcurrentHashMap并不是将每个方法锁定在一个普通的锁上,而是使用单独的锁来分离bucket,从而只锁定了地图的一部分。默认情况下,有16个桶,还有单独的锁用于单独的桶。所以默认的并发级别是16。这意味着理论上任何给定的时间,如果16个线程都要分离bucket,它们都可以访问ConcurrentHashMap。

#17


0  

In general, if you want to use the ConcurrentHashMap make sure you are ready to miss 'updates'
(i.e. printing contents of the HashMap does not ensure it will print the up-to-date Map) and use APIs like CyclicBarrier to ensure consistency across your program's lifecycle.

一般来说,如果您想使用ConcurrentHashMap,请确保您已经准备好错过“更新”(例如,打印HashMap的内容并不保证它会打印最新的Map),并使用循环屏障等api来确保程序生命周期的一致性。

#18


0  

Besides what has been suggested, I'd like to post the source code related to SynchronizedMap.

除了建议之外,我还想发布与SynchronizedMap相关的源代码。

To make a Map thread safe, we can use Collections.synchronizedMap statement and input the map instance as the parameter.

为了使地图线程安全,我们可以使用集合。同步映射语句并将映射实例作为参数输入。

The implementation of synchronizedMap in Collections is like below

在集合中同步映射的实现如下所示

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

As you can see, the input Map object is wrapped by the SynchronizedMap object.
Let's dig into the implementation of SynchronizedMap ,

如您所见,输入映射对象由SynchronizedMap对象包装。让我们深入了解同步映射的实现,

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

What SynchronizedMap does can be summarized as adding a single lock to primary method of the input Map object. All method guarded by the lock can't be accessed by multiple threads at the same time. That means normal operations like put and get can be executed by a single thread at the same time for all data in the Map object.

同步映射的作用可以概括为向输入映射对象的主方法添加一个锁。由锁保护的所有方法不能同时被多个线程访问。这意味着,对于Map对象中的所有数据,像put和get这样的普通操作可以由一个线程同时执行。

It makes the Map object thread safe now but the performance may become an issue in some scenarios.

它使Map对象线程现在是安全的,但是性能在某些场景中可能会成为问题。

The ConcurrentMap is far more complicated in the implementation, we can refer to Building a better HashMap for details. In a nutshell, it's implemented taking both thread safe and performance into consideration.

在实现中,ConcurrentMap要复杂得多,我们可以参考构建一个更好的HashMap以获得详细信息。简而言之,它是在考虑线程安全性和性能的情况下实现的。