<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Java_ConcurrentHashMap</id>
	<title>Java ConcurrentHashMap - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=Java_ConcurrentHashMap"/>
	<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;action=history"/>
	<updated>2026-06-02T19:46:57Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=3794&amp;oldid=prev</id>
		<title>Riguz：​Riguz移动页面Blog:阅读笔记：ConcurrentHashMap至Java ConcurrentHashMap，不留重定向</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=3794&amp;oldid=prev"/>
		<updated>2023-12-19T06:51:55Z</updated>

		<summary type="html">&lt;p&gt;Riguz移动页面&lt;a href=&quot;/index.php?title=Blog:%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0%EF%BC%9AConcurrentHashMap&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Blog:阅读笔记：ConcurrentHashMap（页面不存在）&quot;&gt;Blog:阅读笔记：ConcurrentHashMap&lt;/a&gt;至&lt;a href=&quot;/Java_ConcurrentHashMap&quot; title=&quot;Java ConcurrentHashMap&quot;&gt;Java ConcurrentHashMap&lt;/a&gt;，不留重定向&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月19日 (二) 06:51的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans-CN&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=2545&amp;oldid=prev</id>
		<title>2021年4月28日 (三) 16:19 Riguz</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=2545&amp;oldid=prev"/>
		<updated>2021-04-28T16:19:21Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2021年4月28日 (三) 16:19的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l52&quot;&gt;第52行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第52行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* HashTable是基于Dictionary接口实现的&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* HashTable是基于Dictionary接口实现的&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;HashTable（以及ConcurrentHashMap）都是不允许null值作为Key和Vaule的，主要的原因是因为要支持并发，假设调用`get(key)`得到了null，你是不能确认是key不存在，还是说存在但是值为null。在非并发场景下可以通过&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;`&lt;/del&gt;contains(key)&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;`&lt;/del&gt;来判断是否真的存在，但是在并发场景下，很可能会被其他线程修改。在JDK注释中有这样的解释：&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;HashTable（以及ConcurrentHashMap）都是不允许null值作为Key和Vaule的，主要的原因是因为要支持并发，假设调用`get(key)`得到了null，你是不能确认是key不存在，还是说存在但是值为null。在非并发场景下可以通过&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;syntaxhighlight lang=&quot;java&quot; inline&amp;gt;&lt;/ins&gt;contains(key)&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/ins&gt;来判断是否真的存在，但是在并发场景下，很可能会被其他线程修改。在JDK注释中有这样的解释：&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;gt; The main reason that nulls aren&amp;#039;t allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can&amp;#039;t be accommodated. The main one is that if map.get(key) returns null, you can&amp;#039;t detect whether the key explicitly maps to null vs the key isn&amp;#039;t mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;gt; The main reason that nulls aren&amp;#039;t allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can&amp;#039;t be accommodated. The main one is that if map.get(key) returns null, you can&amp;#039;t detect whether the key explicitly maps to null vs the key isn&amp;#039;t mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l96&quot;&gt;第96行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第96行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;可见get操作没有加任何的锁，而是通过将&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;`&lt;/del&gt;transient volatile Node&amp;lt;K,V&amp;gt;[] table;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;`&lt;/del&gt;将table设置为volatile来保证可见性的。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;可见get操作没有加任何的锁，而是通过将&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;syntaxhighlight lang=&quot;java&quot; inline&amp;gt;&lt;/ins&gt;transient volatile Node&amp;lt;K,V&amp;gt;[] table;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/ins&gt;将table设置为volatile来保证可见性的。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l189&quot;&gt;第189行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第189行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.javatpoint.com/difference-between-hashmap-and-hashtable Difference between HashMap and Hashtable]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* [https://www.javatpoint.com/difference-between-hashmap-and-hashtable Difference between HashMap and Hashtable]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;[[Category:Concurrency]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=2544&amp;oldid=prev</id>
		<title>imported&gt;Riguz：​我们知道HashMap不是Thread-safe的，而HashTable内部采取了同步操作，是线程安全的。然而有趣的是你去看HashTable的文档，它会建议你：如果不要Thread-Safe你就用HashMap吧，否则你用ConcurrentHashMap好了。

一般如果对线程安全有要求，我们有如下的一些选择：

* ConcurrentHashMap
* Hashtable
* Collections.synchronizedMap</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=Java_ConcurrentHashMap&amp;diff=2544&amp;oldid=prev"/>
		<updated>2020-03-19T00:00:00Z</updated>

		<summary type="html">&lt;p&gt;我们知道HashMap不是Thread-safe的，而HashTable内部采取了同步操作，是线程安全的。然而有趣的是你去看HashTable的文档，它会建议你：如果不要Thread-Safe你就用HashMap吧，否则你用ConcurrentHashMap好了。  一般如果对线程安全有要求，我们有如下的一些选择：  * ConcurrentHashMap * Hashtable * Collections.synchronizedMap&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;我们知道HashMap不是Thread-safe的，而HashTable内部采取了同步操作，是线程安全的。然而有趣的是你去看HashTable的文档，它会建议你：如果不要Thread-Safe你就用HashMap吧，否则你用ConcurrentHashMap好了。&lt;br /&gt;
&lt;br /&gt;
一般如果对线程安全有要求，我们有如下的一些选择：&lt;br /&gt;
&lt;br /&gt;
* ConcurrentHashMap&lt;br /&gt;
* Hashtable&lt;br /&gt;
* Collections.synchronizedMap&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Collections.synchronizedMap=&lt;br /&gt;
&lt;br /&gt;
这个实现很粗暴，实际上就是将Map的各个操作都进行了包装和同步：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private static class SynchronizedMap&amp;lt;K,V&amp;gt;&lt;br /&gt;
        implements Map&amp;lt;K,V&amp;gt;, Serializable {&lt;br /&gt;
    private final Map&amp;lt;K,V&amp;gt; m;     // Backing Map&lt;br /&gt;
    final Object      mutex;  &lt;br /&gt;
&lt;br /&gt;
    SynchronizedMap(Map&amp;lt;K,V&amp;gt; m) {&lt;br /&gt;
        this.m = Objects.requireNonNull(m);&lt;br /&gt;
        mutex = this;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
在构造函数中传入了原来的Map，以及一个对象锁（如果不传那就默认是this了）。然后，所有的操作都进行了同步处理：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public boolean containsValue(Object value) {&lt;br /&gt;
    synchronized (mutex) {return m.containsValue(value);}&lt;br /&gt;
}&lt;br /&gt;
public V get(Object key) {&lt;br /&gt;
    synchronized (mutex) {return m.get(key);}&lt;br /&gt;
}&lt;br /&gt;
// ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= HashTable=&lt;br /&gt;
&lt;br /&gt;
HashTable实现线程安全的方式与上面有些类似，对所有需要同步的地方直接进行了同步：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public synchronized int size() {&lt;br /&gt;
    return count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
那么HashMap和HashTable有什么区别呢？除了同步之外，总结下来有以下几点：&lt;br /&gt;
&lt;br /&gt;
* HashMap允许一个null的key，value也可以为null；但是HashTable不允许null作为key或者value&lt;br /&gt;
* HashMap是JDK1.2才引入的&lt;br /&gt;
* HashTable是基于Dictionary接口实现的&lt;br /&gt;
&lt;br /&gt;
HashTable（以及ConcurrentHashMap）都是不允许null值作为Key和Vaule的，主要的原因是因为要支持并发，假设调用`get(key)`得到了null，你是不能确认是key不存在，还是说存在但是值为null。在非并发场景下可以通过`contains(key)`来判断是否真的存在，但是在并发场景下，很可能会被其他线程修改。在JDK注释中有这样的解释：&lt;br /&gt;
&lt;br /&gt;
&amp;gt; The main reason that nulls aren&amp;#039;t allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can&amp;#039;t be accommodated. The main one is that if map.get(key) returns null, you can&amp;#039;t detect whether the key explicitly maps to null vs the key isn&amp;#039;t mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.&lt;br /&gt;
&lt;br /&gt;
= ConcurrentHashMap=&lt;br /&gt;
在Java1.7和1.8中ConcurrentHashMap实现差别较大，在1.7中采用分段锁的方式实现，将Map分为许多个Segment（Segment继承自ReentrantLock）,操作的时候，只会去占用某一个Segment，而其他的Segment不会受到影响。&lt;br /&gt;
&lt;br /&gt;
而在1.8中直接使用CAS+ synchronized来实现。其在内存中的结构与HashMap几乎相同了。&lt;br /&gt;
&lt;br /&gt;
== get操作==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public V get(Object key) {&lt;br /&gt;
    Node&amp;lt;K,V&amp;gt;[] tab; Node&amp;lt;K,V&amp;gt; e, p; int n, eh; K ek;&lt;br /&gt;
&lt;br /&gt;
    // 得到最终的hash值（将高位混合到低位去避免哈希冲突）&lt;br /&gt;
    int h = spread(key.hashCode());&lt;br /&gt;
    if ((tab = table) != null &amp;amp;&amp;amp; (n = tab.length) &amp;gt; 0 &amp;amp;&amp;amp;&lt;br /&gt;
        // (n-1) &amp;amp; h 计算出所在的index值（与HashMap相同）&lt;br /&gt;
        (e = tabAt(tab, (n - 1) &amp;amp; h)) != null) { &lt;br /&gt;
        // 如果哈希值相同，则直接定位到节点，再判断是否equal即可&lt;br /&gt;
        if ((eh = e.hash) == h) {                &lt;br /&gt;
            // 这里比较key是否equal，单纯只凭hashCode是不够的。&lt;br /&gt;
            // 首先比较内存地址是否一致；然后再调用equals方法，是一种优化手段。&lt;br /&gt;
            if ((ek = e.key) == key || (ek != null &amp;amp;&amp;amp; key.equals(ek)))&lt;br /&gt;
                return e.val;&lt;br /&gt;
        }&lt;br /&gt;
        /*&lt;br /&gt;
            Hash值的首位被用作标记位，为负数的hash值是特殊的节点（也就是红黑树化了）&lt;br /&gt;
        */&lt;br /&gt;
        // 如果根据哈希值没有匹配到，那证明可能有哈希冲突，为负数是红黑树则在树中查找&lt;br /&gt;
        else if (eh &amp;lt; 0)                         &lt;br /&gt;
            return (p = e.find(h, key)) != null ? p.val : null;&lt;br /&gt;
        // 否则是普通的链表，在链表中一直朝下找即可&lt;br /&gt;
        while ((e = e.next) != null) {           &lt;br /&gt;
            if (e.hash == h &amp;amp;&amp;amp;&lt;br /&gt;
                ((ek = e.key) == key || (ek != null &amp;amp;&amp;amp; key.equals(ek))))&lt;br /&gt;
                return e.val;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return null;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
可见get操作没有加任何的锁，而是通过将`transient volatile Node&amp;lt;K,V&amp;gt;[] table;`将table设置为volatile来保证可见性的。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
transient volatile Node&amp;lt;K,V&amp;gt;[] table;&lt;br /&gt;
&lt;br /&gt;
static class Node&amp;lt;K,V&amp;gt; implements Map.Entry&amp;lt;K,V&amp;gt; {&lt;br /&gt;
    final int hash;&lt;br /&gt;
    final K key;&lt;br /&gt;
    volatile V val;&lt;br /&gt;
    volatile Node&amp;lt;K,V&amp;gt; next;&lt;br /&gt;
    //...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== put操作==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
final V putVal(K key, V value, boolean onlyIfAbsent) {&lt;br /&gt;
    if (key == null || value == null) throw new NullPointerException();&lt;br /&gt;
    int hash = spread(key.hashCode());&lt;br /&gt;
    int binCount = 0;&lt;br /&gt;
    for (Node&amp;lt;K,V&amp;gt;[] tab = table;;) {&lt;br /&gt;
        Node&amp;lt;K,V&amp;gt; f; int n, i, fh;&lt;br /&gt;
        // 因为是懒加载，第一次插入的时候可能需要初始化&lt;br /&gt;
        if (tab == null || (n = tab.length) == 0)&lt;br /&gt;
            tab = initTable();&lt;br /&gt;
        // 没有找到（节点之前不存在）&lt;br /&gt;
        else if ((f = tabAt(tab, i = (n - 1) &amp;amp; hash)) == null) {&lt;br /&gt;
            // 尝试CAS插入节点到空桶中，如果失败，则会重新走上面的流程进来&lt;br /&gt;
            if (casTabAt(tab, i, null,&lt;br /&gt;
                         new Node&amp;lt;K,V&amp;gt;(hash, key, value, null)))&lt;br /&gt;
                break;                   // no lock when adding to empty bin&lt;br /&gt;
        }&lt;br /&gt;
        // 如果（后面的流程）插入到了红黑树中，会导致首节点改变，所以这个地方需要帮忙更改过来&lt;br /&gt;
        else if ((fh = f.hash) == MOVED)&lt;br /&gt;
            tab = helpTransfer(tab, f);&lt;br /&gt;
        else {&lt;br /&gt;
            V oldVal = null;&lt;br /&gt;
            // f为当前定位到的桶中的第一个节点，将其同步进行后续操作&lt;br /&gt;
            synchronized (f) {&lt;br /&gt;
                // 看看同步之前当前节点是否已经被更改了；如果是则需要重新开始轮回&lt;br /&gt;
                if (tabAt(tab, i) == f) {&lt;br /&gt;
                    // 普通链表&lt;br /&gt;
                    if (fh &amp;gt;= 0) {&lt;br /&gt;
                        binCount = 1;&lt;br /&gt;
                        for (Node&amp;lt;K,V&amp;gt; e = f;; ++binCount) {&lt;br /&gt;
                            K ek;&lt;br /&gt;
                            // 如果已经存在值&lt;br /&gt;
                            if (e.hash == hash &amp;amp;&amp;amp;&lt;br /&gt;
                                ((ek = e.key) == key ||&lt;br /&gt;
                                 (ek != null &amp;amp;&amp;amp; key.equals(ek)))) {&lt;br /&gt;
                                oldVal = e.val;&lt;br /&gt;
                                if (!onlyIfAbsent)&lt;br /&gt;
                                    e.val = value;&lt;br /&gt;
                                break;&lt;br /&gt;
                            }&lt;br /&gt;
                            // 不存在则新增一个节点，插入到链表尾部&lt;br /&gt;
                            Node&amp;lt;K,V&amp;gt; pred = e;&lt;br /&gt;
                            if ((e = e.next) == null) {&lt;br /&gt;
                                pred.next = new Node&amp;lt;K,V&amp;gt;(hash, key,&lt;br /&gt;
                                                          value, null);&lt;br /&gt;
                                break;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                    // 按红黑树处理&lt;br /&gt;
                    else if (f instanceof TreeBin) {&lt;br /&gt;
                        Node&amp;lt;K,V&amp;gt; p;&lt;br /&gt;
                        binCount = 2;&lt;br /&gt;
                        if ((p = ((TreeBin&amp;lt;K,V&amp;gt;)f).putTreeVal(hash, key,&lt;br /&gt;
                                                       value)) != null) {&lt;br /&gt;
                            oldVal = p.val;&lt;br /&gt;
                            if (!onlyIfAbsent)&lt;br /&gt;
                                p.val = value;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if (binCount != 0) {&lt;br /&gt;
                if (binCount &amp;gt;= TREEIFY_THRESHOLD)&lt;br /&gt;
                    treeifyBin(tab, i);&lt;br /&gt;
                if (oldVal != null)&lt;br /&gt;
                    return oldVal;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    addCount(1L, binCount);&lt;br /&gt;
    return null;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* [https://www.javatpoint.com/difference-between-hashmap-and-hashtable Difference between HashMap and Hashtable]&lt;/div&gt;</summary>
		<author><name>imported&gt;Riguz</name></author>
	</entry>
</feed>