3.JUC线程高级-同步容器 ConcurrentHashMap

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: Java5.0 在java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。ConcurrentHashMap 同步容器类是Java5 增加的一个线程安全的哈希表。

Java5.0 在java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。

  • ConcurrentHashMap 同步容器类是Java5 增加的一个线程安全的哈希表。对于多线程的操作,介于HashMap与Hashtable之间。内部采用锁分段机制代替Hashtable 的独占锁。进而提高性能。
  • 此包还提供了设计用于多线程上下文中的Collection 实现:
    ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。
  • 当期望许多线程访问一个给定 collection 时,ConcurrentHashMap 通常优于同步的 HashMap,ConcurrentSkipListMap 通常优于同步的 TreeMap。
  • 当期望的数和遍历远远大于列表的更新数时,CopyOnWriteArrayList 优与同步的 ArrayList。

1. Hashtable 之所以效率低下的原因:

内部使用独占锁机制,特别是遇到大量的复合操作时效率就会很低。

img_06820150b13928285ef6426ecddade31.png

2. ConcurrentHashMap 采用 锁分段 机制:

concurrentLevel分段级别,默认16段(segment)

img_537aa6f6499bed631d373de7543f6d09.png

这里每个分段都是一个独立的锁,这就意味着多个线程并发访问时并行执行,效率瞬间就高了。并且该类内部也提供了一些复合操作的方法。

在JDK1.8之后,jvm底层将ConcurrentHashMap底层的分段锁转换为了 CAS(不会阻塞,不涉及上下文交互) 机制

3. CopyOnWrite 写入并复制

在此之前我们模拟并发修改异常情况:在遍历集合时为集合添加元素

package com.pyy.juc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class TestCopyOnWriteArrayList {
    public static void main(String[] args) {
        HelloThread ht = new HelloThread();

        for(int i = 0; i < 10; i++) {
            new Thread(ht).start();
        }
    }
}

class HelloThread implements Runnable {

    private static List<String> list = Collections.synchronizedList(new ArrayList<String>());

    static {
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {
        Iterator<String> it = list.iterator();

        while(it.hasNext()) {
            System.out.println(it.next());

            list.add("AA");
        }
    }
}

结果:报并发修改异常java.util.ConcurrentModificationException

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at com.pyy.juc.HelloThread.run(TestCopyOnWriteArrayList.java:35)
    at java.lang.Thread.run(Thread.java:745)

如果遇到这样的操作我们可以使用 CopyOnWriteArrayList 并发容器类解决这问题:这个类的底层会在你执行写入之前先复制出一个新的列表再执行写入。
注意:

  • 添加操作多时,效率低,因为每次添加都会进行复制,开销非常大。
  • 适用于迭代(遍历操作)多,同时又考虑并发安全可以使用
目录
相关文章
|
29天前
|
安全
ConcurrentHashMap原如何保证的线程安全?
JDK1.7:使用分段锁,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁 JDK1.8:采用CAS+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全
62 2
|
17天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
27 1
|
29天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
2月前
|
传感器 数据处理 定位技术
多线程;顺序容器;智能指针
【10月更文挑战第14天】多线程的创建创建线程比较简单,C++提供头文件thread,使用std的thread实例化一个线程对象创建。 std::thread 在 #include 头文件中声明,因此使用 std::thread 时需要包含 #include 头文件。
|
3月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
2月前
|
Java C++
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
【多线程】JUC的常见类,Callable接口,ReentranLock,Semaphore,CountDownLatch
36 0
|
2月前
|
传感器 数据处理 定位技术
多线程;顺序容器;智能指针
多线程的创建创建线程比较简单,C++提供头文件thread,使用std的thread实例化一个线程对象创建。 std::thread 在 #include 头文件中声明,因此使用 std::thread 时需要包含 #include 头文件。 #include &lt;iostream&gt; #include &lt;thread&gt; #include &lt;stdlib.h&gt; //sleep using namespace std; void t1() //普通的函数,用来执行线程 { for (int i = 0; i &lt; 10; ++i)
多线程;顺序容器;智能指针
|
3月前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
195 6
【Java学习】多线程&JUC万字超详解
|
3月前
|
传感器 数据处理 定位技术
多线程;顺序容器;智能指针
多线程的创建创建线程比较简单,C++提供头文件thread,使用std的thread实例化一个线程对象创建。 std::thread 在 #include 头文件中声明,因此使用 std::thread 时需要包含 #include 头文件。 #include &lt;iostream&gt; #include &lt;thread&gt; #include &lt;stdlib.h&gt; //sleep using namespace std; void t1() //普通的函数,用来执行线程 { for (int i = 0; i &lt; 10; ++i)
|
4月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
66 1
下一篇
DataWorks