您的位置:首页 > 房产 > 建筑 > Java中HashMap 和 ConcurrentHashMap

Java中HashMap 和 ConcurrentHashMap

2024/10/7 6:42:55 来源:https://blog.csdn.net/m0_68570169/article/details/142136919  浏览:    关键词:Java中HashMap 和 ConcurrentHashMap

`HashMap` 和 `ConcurrentHashMap` 都是 Java 中用来存储键值对的集合类,但它们有不同的设计目标,适用于不同的场景。以下是它们的详细对比和介绍。

### 1. `HashMap` 概述
`HashMap` 是基于哈希表的非同步集合类,主要用于在单线程环境下存储键值对。

#### 特性:
- **线程不安全**:`HashMap` 不是线程安全的,多个线程同时操作时可能会导致数据不一致的问题。如果需要在多线程环境中使用,可以手动进行同步或者使用同步包装器(例如 `Collections.synchronizedMap()`)。
- **允许 `null` 键和值**:`HashMap` 允许一个 `null` 键和多个 `null` 值。
- **性能优越**:由于没有同步开销,在单线程环境下,`HashMap` 的性能非常好。
- **无序**:元素的存储顺序是无序的,不能保证插入的顺序。

#### 示例代码:
```java
import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("Alice", 25);
        map.put("Bob", 30);
        map.put(null, 100); // 允许null键
        map.put("Charlie", null); // 允许null值

        // 遍历HashMap
        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
    }
}
```

### 2. `ConcurrentHashMap` 概述
`ConcurrentHashMap` 是 Java 5 引入的线程安全集合类,主要用于高并发环境下存储键值对。它通过分段锁(Java 8 之后采用 CAS 和少量锁)来确保线程安全,同时提供比 `Hashtable` 更高效的并发性能。

#### 特性:
- **线程安全**:`ConcurrentHashMap` 使用了一种更细粒度的锁机制(分段锁或 CAS 操作),保证线程安全且并发性能优越。在多线程下允许并发读写,而不会出现 `HashMap` 的数据一致性问题。
- **不允许 `null` 键和值**:与 `HashMap` 不同,`ConcurrentHashMap` 不允许 `null` 键或 `null` 值,插入 `null` 会抛出 `NullPointerException`。
- **高效并发**:通过分段锁或无锁(Java 8 之后的 CAS),多个线程可以同时访问不同的分段,降低了锁争用,提高了并发性能。
- **性能较好**:在高并发环境下,`ConcurrentHashMap` 的性能优于 `Hashtable`,因为它并不对整个 Map 加锁。

#### 示例代码:
```java
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        map.put("Alice", 25);
        map.put("Bob", 30);
        // map.put(null, 100); // 不允许null键
        // map.put("Charlie", null); // 不允许null值

        // 遍历ConcurrentHashMap
        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
    }
}
```

### 3. `HashMap` 与 `ConcurrentHashMap` 对比

| 特性                     | `HashMap`                          | `ConcurrentHashMap`                |
|--------------------------|------------------------------------|------------------------------------|
| **线程安全**             | 否,线程不安全                     | 是,线程安全                       |
| **允许 `null` 键和值**    | 允许 `null` 键和 `null` 值         | 不允许 `null` 键和值               |
| **同步机制**             | 无                                 | 分段锁或 CAS(无锁)               |
| **性能**                 | 在单线程环境下性能更优             | 在多线程环境下性能优越             |
| **适用场景**             | 单线程环境或非并发操作场景         | 多线程环境下的并发操作             |
| **迭代器行为**           | 迭代期间会抛出 `ConcurrentModificationException` | 迭代期间不抛异常,支持弱一致性     |
| **扩容机制**             | 负载因子达到 0.75 时扩容           | 负载因子达到 0.75 时扩容,线程安全 |

### 4. Java 8 对 `HashMap` 和 `ConcurrentHashMap` 的优化
- **`HashMap` 的优化**:在 Java 8 之前,`HashMap` 使用链表来处理哈希冲突,而在 Java 8 中,当链表长度超过一定阈值时,它会转换为红黑树结构来优化查询和插入操作。
- **`ConcurrentHashMap` 的优化**:Java 8 中的 `ConcurrentHashMap` 摒弃了原有的分段锁机制,而是采用了一种基于 CAS 和少量锁的方式来进一步提升并发性能。

### 5. `ConcurrentHashMap` 的分段锁原理(Java 7 之前)
在 Java 7 及之前的版本中,`ConcurrentHashMap` 使用了分段锁(Segmented Locking)机制。它将整个 `ConcurrentHashMap` 分为多个 Segment,每个 Segment 都是一个小的 `Hashtable`。多个线程可以同时访问不同的 Segment,实现并发访问。

在 Java 8 中,分段锁的实现被简化,使用 CAS 和少量的锁来优化性能,减少了锁的使用,提高了并发性能。

### 6. 总结
- **`HashMap`** 是在单线程环境中使用的高效集合类,允许 `null` 键和值,但在多线程环境中不安全。
- **`ConcurrentHashMap`** 是为高并发设计的线程安全集合类,不允许 `null` 键和值,适用于多线程环境,并提供更高效的并发性能。
- 在多线程场景下,**`ConcurrentHashMap`** 是替代 **`Hashtable`** 和 **同步化 `HashMap`** 的最佳选择。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com