Vector

ArrayList 的线程安全版本,对所有的修改方法都进行了 synchronized 同步处理。适用于多线程环境下对数据一致性要求高,且读写操作相对比较均衡,不需要很高并发性能的场景。由于所有操作都进行同步,在高并发环境下,性能相对较差

Hashtable

HashMap 的线程安全版本,对每个关键方法都进行了 synchronized 同步处理。在多线程环境下需要一个线程安全的键值对存储结构,并且对数据的读写频率相对均衡时适用。高并发下性能不佳,并且不允许键或值为 null

ConcurrentHashMap

1. 数据结构

在 JDK1.7 中,ConcurrentHashMap 底层数据结构由多个 Segment 组成,Segment 继承自 ReentrantLock,本质上是一个可重入锁,每个 Segment 独立管理一部分数据,相当于一个小型的哈希表。每个 Segment 内部包含一个 HashEntry 数组,用于存储键值对。HashEntry 是一个链表结构,用于解决哈希冲突,新的键值对会插入到链表头部

在 JDK1.8 中,ConcurrentHashMap 底层数据结构是一个 Node 数组,Node 节点用链表或红黑树解决哈希冲突。当链表长度小于等于 8 时,采用链表存储数据。当链表长度大于 8 且数组长度大于 64 时,链表会转化为红黑树

2. 读取原理

在 JDK1.7 中,HashEntry 的 value 和 next 指针都被声明为 volatile 类型,保证内存可见性。不同的 Segment 可以并发访问,多个线程可以同时读取不同 Segment 的数据

在 JDK1.8 中,Node 节点的 value 和 next 指针都被声明为 volatile 类型,保证内存可见性。多个线程可同时读取不同位置的元素,提高并发读性能

3. 写入原理

在 JDK1.7 中,首先需要根据键的哈希值定位到对应的 Segment,然后获取该 Segment的锁。获取锁后,在对应 Segment 的 HashEntry 数组中找到合适的位置,将新的键值对插入到链表头部

在 JDK1.8 中,首先需要根据键的哈希值定位到对应的 Node 数组索引,若该位置为空,利用 CAS 操作将新节点插入,成功则插入完成。若 CAS 插入失败,说明发生哈希冲突。当发生哈希冲突时,若是链表,则对链表头节点加锁,遍历链表插入或更新,若是红黑树,则对红黑树的根节点加锁,按红黑树规则插入或更新

4. 扩容机制

在 JDK1.7 中,当某个 Segment 的 HashEntry 数组的元素数量达到阈值时,该 Segment 会加锁进行扩容操作。扩容时会创建一个新的更大的 HashEntry 数组,然后将原数组中的元素重新哈希并复制到新数组。不同的 Segment 可以独立进行扩容,不会影响其他 Segment 的正常操作

在 JDK1.8 中,当元素数量达到阈值,触发扩容。首先使用 CAS 操作创建一个更大的 Node 数组,然后使用 CAS 操作更新数组中的 Node 节点引用,再对 Node 节点的链表头节点或红黑树根节点使用 synchronized 关键字加锁,进行数据迁移操作。ConcurrentHashMap 采用多线程分段迁移的方式将原数组元素迁移到新数组,不同线程可负责不同段的迁移工作

CopyOnWriteArrayList / CopyOnWriteArraySet

CopyOnWriteArrayList 是一种线程安全的 List 实现,允许在多线程环境下进行并发的读写操作,其核心思想是“写时复制”,即当进行写操作时,会创建一个原数据结构的副本,在副本上进行修改,完成后再将副本替换原数据结构。CopyOnWriteArraySet 与 CopyOnWriteArrayList 的作用与实现类似

当执行写操作时,CopyOnWriteArrayList 会先创建一个当前数组的副本,对副本进行写操作。由于操作的是副本,不会影响到其他线程对原数组的读操作,从而保证了读写之间的并发安全。完成对副本的写操作后,会通过原子操作将原数组的引用替换为指向新的副本数组的引用。在这个替换过程中,使用 volatile 关键字修饰数组引用,保证其他线程能够及时看到更新后的数组。上述整个过程使用 ReentrantLock 锁保证同一时刻只有一个线程能够进行写操作

ConcurrentLinkedQueue

ConcurrentLinkedQueue 是基于链表实现的线程安全队列,采用 CAS 算法实现无锁的并发访问。比如多个线程同时进行出队操作时,每个线程都可以独立地尝试更新头节点的引用,通过 CAS 操作确保只有一个线程能够成功更新,从而实现了无锁的并发访问

BlockingQueue

BlockingQueue 是阻塞队列,内部使用锁机制实现线程安全。当队列已满时,尝试向队列中添加元素的线程会被阻塞,直到队列有空间可用。当队列为空时,尝试从队列中获取元素的线程会被阻塞,直到队列有元素可获取

具体参考:https://www.cnblogs.com/Yee-Q/p/14580034.html

同步包装器

Java 同步包装器是指通过 Collections 类的静态方法将非线程安全的集合转换为线程安全的集合,主要包括以下几种:

  • synchronizedList:把普通的 List 转换为线程安全的列表。通过对 List 的所有操作添加同步锁,确保同一时刻只有一个线程能够访问列表,避免并发访问时出现数据不一致等问题,如 List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
  • synchronizedMap:把普通的 Map 转换为线程安全的映射。在对 Map 进行操作时,都会进行同步处理,保证多线程环境下 Map 的操作安全,如:Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
  • synchronizedSet:把普通的 Set 转换为线程安全的集合。通过同步机制,确保在多线程访问 Set 时,元素的添加、删除等操作不会出现并发问题,如:Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());

Java 线程安全的集合的更多相关文章

  1. Java——线程安全的集合

    线程安全的集合    java.util.concurrent包:ConcurrentHashMap,ConcurrentSkipListMap,ConcurrentSkipListSet,Concu ...

  2. java利用线程池处理集合

    java利用线程池处理集合 2018年07月23日 17:21:19 衍夏成歌 阅读数:866   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/s ...

  3. java 多线程 线程安全及非线程安全的集合对象

    一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用.防止出现数据不一致或 ...

  4. java 中如何声明线程安全的集合 set, map 和list

    线程安全的集合 http://blog.sina.com.cn/s/blog_508938e10102v1ig.html //make thread-safe list List MyStrList ...

  5. java 中如何声明线程安全的集合 set, map 和list【转】

    线程安全的集合 引用自 http://blog.sina.com.cn/s/blog_508938e10102v1ig.html //make thread-safe list List MyStrL ...

  6. Java中线程安全的集合

    如果多线程并发的访问与一个数据结构,那么很容易破坏一个数据结构. 例如,一个线程可能要向一个散列表中插入一条数据的过程中,被剥夺了控制权.如果另外一个线程也开始遍历同一个链表,很可能造成混乱,抛出异常 ...

  7. Java基础面试:集合、内部类、线程

    package test; import java.util.Hashtable; import java.util.Map; public class test { public static St ...

  8. Java多线程理解:线程安全的集合对象

    1.概念介绍 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不会出现数据不一致或者数据污染. 线程不安全就 ...

  9. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  10. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

随机推荐

  1. Spring Boot中通过RabbitTemplate主动pull(get)消息的例子

    import java.util.Properties; import java.util.function.Consumer; import org.slf4j.Logger; import org ...

  2. Qt开源作品26-通用按钮地图效果

    一.前言 在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,安防领域一般用来表示防区或者设备,可以直接显示防区号,有多种状态颜 ...

  3. g2o编译出现的问题及解决办法 By not providing "FindG2O.cmake" in CMAKE_MODULE_PATH this project has

    在安装完该g2o之后 运行一些程序 如高翔的ch6 代码会出现如下错误: CMake Warning at CMakeLists.txt:10 (FIND_PACKAGE): By not provi ...

  4. C Primer Plus 第6版 第六章 编程练习参考答案

    编译环境VS Code+WSL GCC 源码请到文末下载 .注意:本章部分题目中用到了math.h 用gcc编译时加上-lm参数. /*第1题*************************/ #i ...

  5. 今天记录一下vue更改时间格式的js

    首先定义js文件,我这边定义为date.js,里面包含了增加零的处理 //date.jsexport function formatDate(date, fmt) { if (/(y+)/.test( ...

  6. 基于wvp-GB28181-pro 与 ZLMediaKit 的国标服务器

    官方教程 wvp-GB28181-pro 与 ZLMediaKit 的联调手册 wvp-GB28181-pro wiki ZLMediaKit 基于C++11的高性能运营级流媒体服务框架 地址:Git ...

  7. RPC简介及框架选择-copy

    简单介绍RPC协议及常见框架,对比传统restful api和RPC方式的优缺点.常见RPC框架,gRPC及序列化方式Protobuf等 HTTP协议 http协议是基于tcp协议的,tcp协议是流式 ...

  8. ClickHouse-5操作

    ClickHouse操作手册由以下主要部分组成: 安装要求 监控 故障排除 使用建议 更新程序 访问权限 数据备份 配置文件 配额 系统表 服务器配置参数 如何用ClickHouse测试你的硬件 设置 ...

  9. Superset 稀奇古怪的bug

    1.filterbox 及 native filter 等组件里面,日期筛选器下拉框,显示的不是日期格式,而是时间戳格式,如: 解决方法: 修改superset\utils\core.py 里面的js ...

  10. linux:lamp环境

    关于LAMP LAMP搭建 安装php和Apache 先装php,因为安装php有apache的依赖包 yum install php 启动Apache service httpd start 启动成 ...