ConcurrentHashMap 中put()方法简介说明

欣喜 Java经验 发布时间:2025-01-26 14:31:53 阅读数:4782 1
下文笔者讲述ConcurrentHashMap之put()方法简介说明,如下所示

ConcurrentHashMap简介

`ConcurrentHashMap`是Java中
  用于在多线程环境中高效处理并发读写操作的哈希表实现
  它提供了比`Hashtable`更好的性能
   因为`ConcurrentHashMap`使用分段锁(segment-based locking)
     或
   更细粒度的锁机制来减少争用 

`put()`方法详解

`ConcurrentHashMap`的`put()`方法
     用于将键值对插入到映射中
  如果指定的键已经存在
     则更新其对应的值
	   该方法是线程安全的
	    且在高并发环境下表现良好

方法签名

public V put(K key, V value)

参数说明:
   `key`:要存储的键
   `value`:与键关联的值
  
返回值:
  返回先前与指定键关联的值
  如果没有找到则返回 `null`。

内部实现

1. **分段锁机制(JDK 7 及之前版本)**
   - 在 JDK 7 及之前的版本中
     `ConcurrentHashMap` 使用分段锁(segments)来实现并发控制
	  每个 segment 实际上是一个小型的哈希表
	   且每个 segment 都有自己的锁。
	   这样可以允许多个线程同时访问不同的 segment,从而提高并发性能。
   
2. **CAS 和锁分离(JDK 8 及之后版本)**
   - 在JDK 8及之后的版本中
    `ConcurrentHashMap`
	  引入更细粒度的锁机制和无锁算法(如 CAS 操作)
	    它使用多个桶(bins)
		  每个桶都有自己的锁
		   对于常见的读操作
		    `ConcurrentHashMap` 使用无锁的方式进行优化
			 而对于写操作(如 `put`)
			   它会尝试使用 CAS 操作来避免不必要的锁竞争

主要步骤

1. **计算哈希码**
   - 计算键的哈希码,并根据哈希码确定应该放置在哪个桶中。

2. **检查桶的状态**
   - 如果桶为空,则直接创建一个新的节点并插入。
   - 如果桶中有链表或红黑树,则遍历链表或树,查找是否存在相同的键。

3. **更新或插入**
   - 如果找到了相同的键,则更新其值,并返回旧值。
   - 如果没有找到相同的键,则插入新的键值对。

4. **调整结构**
   - 如果插入后链表长度超过一定阈值(通常是 8),则将链表转换为红黑树以提高查找效率。
   - 如果删除操作导致红黑树节点数过少(通常小于 6),则将红黑树转换回链表。

以下是一个简单的示例,展示了如何使用 `ConcurrentHashMap` 的 `put()` 方法:
 
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        // 创建一个 ConcurrentHashMap
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

        // 插入键值对
        map.put("java1", 23);
        map.put("java2", 18);

        // 更新已有的键值对
        Integer oldValue = map.put("java1", 66);
        System.out.println("更新前的值: " + oldValue); // 输出: 更新前的值: 23

        // 尝试插入已存在的键
        oldValue = map.put("java2", 28);
        System.out.println("更新前的值: " + oldValue); // 输出: 更新前的值: 18

        // 打印最终结果
        System.out.println("最终的映射: " + map); // 输出: 最终的映射: {java1=23, java2=18}
    }
}

线程安全性

`ConcurrentHashMap`之`put()`方法是线程安全的

- **读操作**:读操作(如 `get()`)在大多数情况下是无锁的
     利用了 Java 内存模型中的可见性保证。
- **写操作**:写操作(如 `put()`、`remove()`)使用细粒度的锁
   或 CAS 操作来确保线程安全。

### 性能优化

1. **细粒度锁**
   - `ConcurrentHashMap` 使用细粒度的锁机制,允许多个线程同时访问不同的桶,减少了锁争用。

2. **无锁读取**
   - 对于读操作,`ConcurrentHashMap` 使用无锁的方式进行优化,提高了读操作的性能。

3. **CAS 操作**
   - 使用 CAS 操作(Compare-And-Swap)来避免不必要的锁竞争,进一步提升了并发性能。

### 注意事项

- **容量和加载因子**:可以通过构造函数指定初始容量和加载因子,以优化性能。合理的初始容量可以减少扩容操作的频率。
- **并发级别**:在 JDK 7 中,`ConcurrentHashMap` 有一个 `concurrencyLevel` 参数,用于指定并发线程的数量。虽然在 JDK 8 中这个参数的影响变小了,但在某些场景下仍然可以提供一定的性能优化。


总结
- **线程安全**:`ConcurrentHashMap` 的 `put()` 方法是线程安全的,适用于高并发环境。
- **性能优化**:通过细粒度锁、无锁读取和 CAS 操作,`ConcurrentHashMap` 提供了高效的并发性能。
- **内部实现**:在 JDK 8 及之后版本中,`ConcurrentHashMap` 使用更细粒度的锁机制和无锁算法来减少争用。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202501/17378731548241.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者