【亮剑】Java中的并发容器ConcurrentHashMap,它在JDK1.5中引入,用于替换HashTable和SynchronizedMap

简介: 【4月更文挑战第30天】本文介绍了Java中的并发容器ConcurrentHashMap,它在JDK1.5中引入,用于替换HashTable和SynchronizedMap。文章展示了创建、添加、获取、删除和遍历元素的基本用法。ConcurrentHashMap的内部实现基于分段锁,每个段是一个独立的Hash表,通过分段锁实现并发控制。每个段内部采用数组+链表/红黑树的数据结构,当冲突过多时转为红黑树优化查询。此外,它有扩容机制,当元素超过阈值时,会逐段扩容并翻倍Segment数量,以保持高性能的并发访问。

一、引言

在多线程环境下,为了保证数据的一致性和并发性能,我们通常会使用到并发容器。而在Java中,ConcurrentHashMap就是一种非常常用的并发容器。它是JDK1.5中引入的,用于替代HashTable和SynchronizedMap等同步容器,提供了更好的并发性能。本文将详细介绍ConcurrentHashMap的使用方法及其内部实现原理。

二、ConcurrentHashMap的使用方法

  1. 创建ConcurrentHashMap对象
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
   
    public static void main(String[] args) {
   
        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
    }
}
  1. 添加元素
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
   
    public static void main(String[] args) {
   
        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("one", 1);
        concurrentHashMap.put("two", 2);
        concurrentHashMap.put("three", 3);
    }
}
  1. 获取元素
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
   
    public static void main(String[] args) {
   
        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("one", 1);
        concurrentHashMap.put("two", 2);
        concurrentHashMap.put("three", 3);

        Integer one = concurrentHashMap.get("one");
        System.out.println("one: " + one);
    }
}
  1. 删除元素
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
   
    public static void main(String[] args) {
   
        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("one", 1);
        concurrentHashMap.put("two", 2);
        concurrentHashMap.put("three", 3);

        concurrentHashMap.remove("one");
    }
}
  1. 遍历元素
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
   
    public static void main(String[] args) {
   
        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put("one", 1);
        concurrentHashMap.put("two", 2);
        concurrentHashMap.put("three", 3);

        for (String key : concurrentHashMap.keySet()) {
   
            System.out.println("Key: " + key + ", Value: " + concurrentHashMap.get(key));
        }
    }
}

三、ConcurrentHashMap的内部实现原理

  1. 分段锁(Segment)

ConcurrentHashMap的核心思想是将整个Map分为N个Segment,每个Segment独立维护一部分数据。这样在进行put、remove等操作时,只需要锁定当前Segment,而不需要锁定整个Map,从而提高并发性能。默认情况下,ConcurrentHashMap会创建16个Segment。

  1. 数据结构

每个Segment内部使用了一个数组来存储键值对,数组的索引通过hashCode计算得到。当发生哈希冲突时,会使用链表或红黑树来解决。当链表长度超过一定阈值时,会转换为红黑树以提高查询效率。

  1. 扩容机制

当某个Segment的元素个数超过阈值时,会触发扩容操作。扩容时,会创建一个新的数组,并将旧数组的数据迁移到新数组中。同时,Segment的数量也会翻倍。为了减少锁的粒度,ConcurrentHashMap采用了逐段扩容的策略,每次只扩容一个Segment。

四、总结

本文详细介绍了ConcurrentHashMap的使用方法及其内部实现原理。通过分段锁的设计,ConcurrentHashMap在保证数据一致性的同时,提供了较好的并发性能。在实际应用中,我们可以根据需要选择合适的并发容器,以提高系统的性能。

相关文章
|
3天前
|
缓存 安全 Java
【Java面试——并发基础、并发关键字】
随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略: 先进行操作,如果没有其它线程争用共享数据,那操作就成功了,否则采取补偿措施(不断地重试,直到成功为止)。这种乐观的并发策略的许多实现都不需要将线程阻塞,因此这种同步操作称为非阻塞同步。 乐观锁需要操作和冲突检测这两个步骤具备原子性,这里就不能再使用互斥同步来保证了,只能靠硬件来完成。硬件支持的原子性操作最典型的是: 比较并交换(Compare-and-Swap,CAS)。CAS 指令需要有 3 个操作数,分别是内存地址 V、旧的预期值 A 和新值 B。当执行操作时,只有当 V 的值等于 A,才将 V 的值更新为 B。
|
3天前
|
缓存 安全 Java
Java的线程池与并发工具类技术性文章
Java的线程池与并发工具类技术性文章
10 0
|
3天前
|
监控 Java 编译器
Java的内存模型与并发控制技术性文章
Java的内存模型与并发控制技术性文章
13 2
|
3天前
|
安全 Java 程序员
Java的迭代器与并发集合的技术性文章
Java的迭代器与并发集合的技术性文章
5 0
|
8天前
|
安全 Java 开发者
探索Java中的多线程编程与并发控制
多线程编程是Java编程中不可或缺的一部分,它允许程序同时执行多个任务,从而显著提高程序的整体性能。然而,多线程编程也带来了诸如数据不一致、死锁等并发问题。本文将深入探讨Java中的多线程编程技术,包括线程的创建、同步与通信,并介绍几种常用的并发控制策略,旨在帮助读者更好地理解并发编程的复杂性和挑战,并学会如何编写高效、安全的并发程序。
|
10天前
|
缓存 安全 Java
JAVA多线程编程与并发控制
```markdown Java多线程编程与并发控制关键点:1) 通过Thread或Runnable创建线程,管理线程状态;2) 使用synchronized关键字和ReentrantLock实现线程同步,防止数据竞争;3) 利用线程池(如Executors)优化资源管理,提高系统效率。并发控制需注意线程安全,避免死锁,确保程序正确稳定。 ```
|
16天前
|
算法 Java 程序员
Java中的线程同步与并发控制
【5月更文挑战第18天】随着计算机技术的不断发展,多核处理器的普及使得多线程编程成为提高程序性能的关键。在Java中,线程是实现并发的一种重要手段。然而,线程的并发执行可能导致数据不一致、死锁等问题。本文将深入探讨Java中线程同步的方法和技巧,以及如何避免常见的并发问题,从而提高程序的性能和稳定性。
|
14天前
|
Prometheus 监控 Cloud Native
构建高效稳定的Docker容器监控体系
【5月更文挑战第20天】 在微服务架构日益普及的今天,Docker作为其重要的实现技术之一,承载着大量应用的运行。然而,随之而来的是对于容器健康状态、资源使用情况以及性能指标的监控需求急剧增加。本文旨在探讨构建一个高效且稳定的Docker容器监控体系,不仅涵盖了监控工具的选择与配置,还详细阐述了监控数据的分析与处理流程。通过精心设计的监控策略和实时响应机制,我们能够确保系统的稳定性,并及时发现及处理潜在的问题。
|
3天前
|
Docker 容器
docker: 如何不新建容器 修改运行容器的端口
docker: 如何不新建容器 修改运行容器的端口
|
3天前
|
数据管理 Linux Docker
docker 数据管理 与容器互联
docker 数据管理 与容器互联