【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )

简介: 【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )

文章目录

I . Java 集合的线程安全概念 ( 加锁同步 )

II . 线程不安全集合 ( 没有并发需求 推荐使用 )

III . 集合属性说明

IV . 早期的线程安全集合 ( 不推荐使用 )

V . 推荐使用的线程安全集合 ( 推荐使用 )

VI . CopyOnWrite 机制



I . Java 集合的线程安全概念 ( 加锁同步 )


1 . 线程安全问题引入 : 使用 Java 集合时 , 不可避免的要在多线程访问集合 , 如果线程安全处理不当 , 就会造成不可预知的故障 ;



2 . 加锁阻塞实现线程安全 : 当多线程操作 Java 集合时 , 使用 synchronized 关键字 加锁阻塞任何对集合的操作 , 修改完毕后 , 解除阻塞 , 防止出现多线程操作 , 出现数据污染 ;



3 . 加锁前后性能对比 : 如果将集合加锁 , 显然会降低程序的性能 , 普通集合 要比 线程安全集合 性能高 ;



4 . 线程安全与性能最佳实践 :



① 线程不安全操作 ( 保证性能 ) : 如果不需要多线程操作集合 , 那么直接使用线程不安全集合即可 , 使性能达到最高 ;


② 线程安全操作 ( 保证正确性 ) : 尽量避免自己手动使用 synchronized 关键字加锁 , synchronized 开销很大 , 消耗性能 ; 推荐使用 JDK 中提供的 java.util.concurrent 包线程安全集合 ;




II . 线程不安全集合 ( 没有并发需求 推荐使用 )


线程不安全的集合 : Java 中的最基础的集合 , 如果没有并发需求 , 推荐使用这些集合 , 其性能高 ; 这些类都定义在 java.utils 包下 ; 线程安全集合都定义在 java.util.concurrent 包下 ;



1 . List 集合 : ArrayList , LinkedList ; 有序元素集合 , 每个元素都有一个索引 ( 从 0 计数 ) ;



① ArrayList : 底层数据结构是 数组 , 通过下标可快速查询 , 查询 修改 性能高 , 增加 删除 性能低 ;


② LinkedList : 底层数据结构是 链表 , 查询 修改 性能低 , 增加 删除 性能高 ;



2 . Set 集合 : HashSet , TreeSet ; 不能包含重复元素 ; 注意 null 元素也算一个元素 , 只能有一个 ;



① HashSet : 底层数据结构是 哈希表 ; 元素无序 , 唯一 ; 元素类需要重写 hashCode 和 equals 两个方法 , 保证唯一性 ;


② TreeSet : 底层数据结构是 红黑树 ; 元素有序 , 唯一 ; 元素类需要重写 hashCode 和 equals 两个方法 , 保证唯一性 ; 使用排序机制 ( 自然排序 / 比较器排序 ) 保证有序性 ;


自然排序 : 元素类需要实现 Compareable 接口 , 覆盖 compareTo 方法 ; 两个排序策略二选一即可 ;

比较器排序 : TreeSet 初始化时 , 设置 Comparator 比较器 ; Comparator 是接口 , 需重写 compare 方法 ;

③ LinkedHashSet : 底层数据结构是 哈希表 和 链表 ; HashSet 派生类 , 其操作与 HashSet 一致 , 没有定义额外的方法 ;



HashSet 与 TreeSet 二者对比 : HashSet 性能高于 TreeSet , 但是不能排序 ;



3 . Map 集合 : HashMap , LinkedHashMap , TreeMap ;



① HashMap : 键 ( Key ) 使用哈希表维护 , 注意元素存放顺序 , 其中的 元素添加顺序 并不是 数据存放顺序 ;


② LinkedHashMap : HashMap 派生类 , Key 除了使用 哈希表 保证其唯一性之外 , 还使用 链表 保证了其 顺序性 , 元素添加顺序 ( 访问顺序 ) 就是 数据的存放顺序 ;


③ TreeMap : Key 使用红黑树维护 , Key 需要使用排序机制 ( 自然排序 / 比较器排序 ) 保证有序性 ;


自然排序 : 元素类需要实现 Compareable 接口 , 覆盖 compareTo 方法 ; 两个排序策略二选一即可 ;

比较器排序 : TreeSet 初始化时 , 设置 Comparator 比较器 ; Comparator 是接口 , 需重写 compare 方法 ;


上述 Hash , Tree , LinkedHash 等都是针对键 ( Key ) 进行维护的 ; 即使用 哈希表 , 红黑树 , 链表哈希表维护键 ( Key ) ;




III . 集合属性说明


1 . Hash : 使用哈希表实现 , 如 HashSet , HashMap , 目的是为了保证其元素唯一性 ;


① 特点 : 元素唯一 ;


① 定制 : 需要保证唯一元素类需要重写 hashCode 和 equals 两个方法 ;



2 . Array : 使用数组实现 , 如 ArrayList ;


① 特点 : 有序 , 下标访问 ;



3 . Linked : 使用链表实现 , 如 LinkedList , 其目的是为了保证有序性 ;


① 特点 : 有序 ;



4 . Tree : 使用红黑树实现 , 如 TreeSet , TreeMap , 其目的是为了保证插入的元素自动排序 ;


① 特点 : 自动排序 ;


② 实现 : 使用排序机制 ( 自然排序 / 比较器排序 ) 保证有序性 ;


自然排序 : 元素类需要实现 Compareable 接口 , 覆盖 compareTo 方法 ; 两个排序策略二选一即可 ;

比较器排序 : TreeSet 初始化时 , 设置 Comparator 比较器 ; Comparator 是接口 , 需重写 compare 方法 ;



IV . 早期的线程安全集合 ( 不推荐使用 )


下面讲的 Vector , HashTable 集合虽然线程安全 , 但是性能很低 , 不推荐使用 ; 已经弃用的类就不再详细解析了 ;



1 . 线程安全 List 集合 :



① Vector ( 弃用 ) : 与 ArrayList 功能与实现基本相同 , 方法前使用 synchronize 关键字同步 ;


② Stack : 栈 结构 , 元素后进先出 , Vector 子类 , 是线程安全的 ;



2 . 线程安全 Map 集合 : HashTable ( 弃用 ) , 与 HashMap 功能相同 , 方法前使用 synchronize 关键字同步 ; HashTable 键值都不能为空 , 否则会报空指针异常 ;




V . 推荐使用的线程安全集合 ( 推荐使用 )


java.util.concurrent 包提供了一系列线程并发工具 , 如 并发锁 , 执行器 , 原子类 , 并发控制类 , 阻塞队列 , 并发集合 , 这里我们先讨论并发集合 , 其余在 Java 并发 中研究 ;



1 . 推荐使用的线程安全集合 : java.util.concurrent 包下的 线程安全集合 ;



① 实现原理 : 也是通过加锁实现线程安全 , 但是其加锁力度很细 , 如区分读写加锁 , 分段加锁 ;


② 优势 : 兼顾了性能与线程安全 , 在保证线程安全的前提下 , 最大限度提高性能 ;


③ 注意 : 这些线程安全集合性能低于普通集合 , 如果不需要多线程访问 , 优先使用普通集合 ;



2 . 与早期的线程安全集合对比 :



① 早期的线程安全集合 : 全部操作都加锁 , 多线程访问几乎每个操作都会阻塞 , 性能很低 ;


② java.util.concurrent 包的线程安全集合 : 加锁的力度很细 , 大部分的线程操作不会加锁 , 没有冲突 , 性能比早期线程略高 , 比现场不安全的线程低 ;



3 . concurrent 包的线程安全集合 : concurrent 包中提供了一系列线程安全的集合 , List , Map , Set , Queue 都有对应的线程安全容器 ;



① List 集合 : CopyOnWriteArrayList ;


② Set 集合 : CopyOnWriteArraySet , ConcurrentSkipListSet ;


③ Map 集合 : ConcurrentMap , ConcurrentHashMap , ConcurrentSkipListMap , ConcurrentNavigableMap ;


④ Queue 队列 : ConcurrentLinkedQueue , ConcurrentLinkedDeque ;




VI . CopyOnWrite 机制


1 . 集合元素修改 ( 加锁并复制 ) : 顾名思义就是在修改集合中的元素时 , 不直接操作当前的集合 , 而是先把集合拷贝一份 , 然后在新的集合中进行修改操作 , 最后将引用指向新的集合 ;



① 修改操作 : add , remove , clear , set 等操作都是加锁 ;


② 本质 : 相当于每次修改都创建了一个新集合 ;


③ 写入互斥 : 多个线程同时修改集合的数据是互斥的 ;



2 . 集合元素读取 ( 不加锁 ) : CopyOnWrite 集合的 get 方法不加锁 , 因为其修改集合时不是修改当前的集合 , 当前集合不会出现数据污染 ;


① 同时读取 : CopyOnWrite 集合支持多个线程同时读取集合数据 ;



3 . 缺陷 :



① 性能 : 每次修改集合 , 都要将整个集合复制一次 , 如何集合很大 , 并且修改频繁 , 那么会导致性能很低 ;


② 实时性 : 读取的时候 , 有可能线程正在被修改 , 读取完毕后 , 有可能集合已经更新了 , 当前读取的数据已经过时 , 不能保证数据的实时性 ;



4 . 适用场景 : CopyOnWrite 机制的集合适用于查询多 , 修改少 , 数据量小的集合 ; 数据量过大 , 或修改频繁 , 性能很低 ;


目录
相关文章
|
23天前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
88 1
|
23天前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
92 2
|
25天前
|
存储 算法 安全
Java集合框架:理解类型多样性与限制
总之,在 Java 题材中正确地应对多样化与约束条件要求开发人员深入理解面向对象原则、范式编程思想以及JVM工作机理等核心知识点。通过精心设计与周密规划能够有效地利用 Java 高级特征打造出既健壮又灵活易维护系统软件产品。
54 7
|
2月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
198 100
|
2月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
217 101
|
2月前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
2月前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
104 0
|
2月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
155 16

热门文章

最新文章

下一篇
开通oss服务