线程不安全的集合

集合概述

Java中除了以Map结尾的类之外,其他类都实现了Collection接口,并且以Map结尾的类都实现了Map接口。

List,Set,Map的区别

List:存储的元素是有序的,可重复的
Set:存储的元素是无序的,不可重复的
Map:使用键值对存储,key是无序的,不可重复的;value是无序的,可重复的。每个键最多映射到一个值

集合框架底层数据结构

List

Arralist:Object[] 数组
Vector:Object[] 数组
LinkedList:双向链表(JDK1.6之前的是循环链表,JDK1.7取消了循环)

Set

HashSet:(无序,唯一)基于HashMap实现的,底层采用HashMap来保存元素
LinkedHashSet:它是HashSet的子类,内部通过LinkedHashMap来实现的。类似于LinkedHashMap内部基于HashMap实现的一样,有一定区别
TreeSet:(有序,唯一)红黑树

Map

HashMap:JDK1.8之前的HashMap由数组和链表组成的,数组是HashMap的主体,链表是主要为了解决哈希冲突而存在的。JDK1.8以后,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认是8)【将链表转换成红黑树前会判断,如果当前数组的长度小于64,那么会选择先进行数组扩容,而不是转换为红黑树】时,将链表转化为红黑树,以减少搜索时间。;
LinkedHashMap:它继承自HashMap,底层是基于拉链式散列结构,即由数组和链表或红黑树组成。另外,LinkedHashMap在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
HashTable:数组+链表组成,数组是HashMap的主体,链表是为了解决哈希冲突而存在的。
TreeMap:红黑树

如何选用集合?

根据键值获取元素值——Map接口下的集合
需要排序时选择——TreeMap
不需要排序时选择——HashMap
需要保证线程安全——ConcurrentHashMap

需要存放元素值——Collection接口下的集合

需要保证元素唯一——Set接口(TreeSet或者HashSet)

不需要保证元素唯一——List接口(ArrayList或者LinkedList)

为什么要使用集合?

需要保存一组类型相同的数据时,用一个容器来保存,这个容器是数组,但是使用数组存储对象有一定的弊端,因为在实际开发中,存储的数据的类型有很多种,集合用来存储多个数据的。
数组的缺点是声明之后长度不可变,同时声明数组时的数据类型也决定了数组存储的数据的类型。数组存储数据是有序的,可重复的,特点单一;但是集合提高了数据存储的灵活性,Java集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据。

Iterator 迭代器

Iterator 对象称为迭代器(设计模式的⼀种),迭代器可以对集合进⾏遍历,但每⼀个集合内部的数据结构可能是不相同的,所以每⼀个集合”存取“都很可能是不⼀样的,虽然我们可以⼈为地在每⼀个类中定义 hasNext()——集合中是否还有元素和next()——获得集合中的下一个元素,这样做会让整个集合体系过于臃肿。于是就有了迭代器。

迭代器的好处

迭代器是将这样的⽅法抽取出接⼝,然后在每个类的内部,定义⾃⼰迭代⽅式,这样做就规定了整个集合体系的遍历⽅式都是 hasNext() 和 next() ⽅法,使⽤者不⽤管怎么实现的,会⽤即可。迭代器的定义为:提供⼀种⽅法访问⼀个容器对象中各个元素,⽽⼜不需要暴露该对象的内部细节。
迭代器的用处:
Iterator 主要是⽤来遍历集合⽤的,它的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出ConcurrentModificationException 异常。

举例说明迭代器的使用(遍历HashMap)

Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "C++");
map.put(3, "PHP");
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
 Map.Entry<Integer, String> entry = iterator.next();
 System.out.println(entry.getKey() + entry.getValue());
}

线程不安全的集合如何解决?

Arraylist , LinkedList , Hashmap , HashSet , TreeSet , TreeMap , PriorityQueue 都是线程不安全的
解决办法:使⽤线程安全的集合来代替
使⽤线程安全的集合的话, java.util.concurrent包中提供了很多并发容器:

  1. ConcurrentHashMap : 可以看作是线程安全的 HashMap
  2. CopyOnWriteArrayList :可以看作是线程安全的 ArrayList ,在读多写少的场合性能⾮常好,远远好于 Vector
  3. ConcurrentLinkedQueue :⾼效的并发队列,使⽤链表实现。可以看做⼀个线程安全的LinkedList ,这是⼀个⾮阻塞队列
  4. BlockingQueue : 这是⼀个接⼝,JDK 内部通过链表、数组等⽅式实现了这个接⼝。表示阻塞队列,⾮常适合⽤于作为数据共享的通道
  5. ConcurrentSkipListMap :跳表的实现。这是⼀个 Map ,使⽤跳表的数据结构进⾏快速查找
<think>好的,我现在需要回答用户关于Java线程安全集合类的问题。首先,用户想知道线程安全集合类列表,特别是Java并发集合。我需要参考之前提供的引用内容,确保回答准确。 首先,引用[1]提到了ConcurrentHashMap,这是Java并发包中的一个重要类。引用[2]和[3]也提到了一些传统的线程安全类,比如Vector、HashTable、Stack,但这些已经被标记为建议使用,因为它们的同步方法效率高。引用[3]还提到Java推荐使用并发包中的类,比如ConcurrentHashMap、ConcurrentLinkedQueue、CopyOnWriteArrayList等。 接下来,我需要整理这些信息,区分传统的线程安全集合Java并发包中的现代实现。传统类虽然线程安全,但性能较差,所以现在多用并发包中的替代品。然后,我需要列出每个类及其特点,比如ConcurrentHashMap采用分段锁或CAS,CopyOnWriteArrayList适合读多写少的场景。 同时,用户可能想知道为什么ArrayList是线程安全的,以及如何安全地在多线程中使用它,比如使用Collections.synchronizedList或者CopyOnWriteArrayList。这部分内容需要包括在回答中,以提供解决方案。 最后,生成相关问题,帮助用户进一步了解。例如,ConcurrentHashMap的实现原理,或者如何选择适合的线程安全集合类。确保问题覆盖用户可能感兴趣的方向,比如性能比较、使用场景等。 需要确保回答结构清晰,分点列出传统和现代的实现,并解释各自的优缺点。同时,代码示例部分要正确使用格式,比如用反引号包裹Java代码块,展示如何创建并发集合实例。注意使用中文,避免技术术语错误,并正确引用来源。</think>### Java线程安全集合类详解 在Java线程环境下,线程安全集合类通过同步机制确保数据一致性。以下分类说明: --- #### 一、传统线程安全集合(已逐渐被替代) 1. **Vector** 内部方法使用`synchronized`修饰,线程安全但性能差。 ```java Vector<String> vector = new Vector<>(); ``` 2. **HashTable** 类似Vector,所有方法同步,性能低且支持`null`键值。 ```java Hashtable<Integer, String> hashtable = new Hashtable<>(); ``` 3. **Stack** 继承自Vector,同步导致单线程场景下效率低[^3]。 --- #### 二、Java并发包(`java.util.concurrent`)中的现代实现 1. **ConcurrentHashMap** 采用分段锁(JDK7)或CAS+synchronized(JDK8+),高并发下性能优异[^1][^3]。 ```java ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); ``` 2. **CopyOnWriteArrayList** 写操作时复制新数组,适合读多写少场景。 ```java CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); ``` 3. **ConcurrentLinkedQueue** 基于无锁算法(CAS)实现的线程安全队列[^2]。 ```java ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>(); ``` 4. **BlockingQueue接口实现类** - **ArrayBlockingQueue**:固定大小的阻塞队列 - **LinkedBlockingQueue**:可选有界或无界队列 ```java BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10); ``` --- #### 三、通过工具类转换线程安全集合 使用`Collections.synchronizedXXX`包装非安全集合: ```java List<String> synList = Collections.synchronizedList(new ArrayList<>()); Map<String, Integer> synMap = Collections.synchronizedMap(new HashMap<>()); ``` --- #### 四、线程安全集合的典型问题 - **ArrayList的并发修改异常** 多线程同时修改导致`ConcurrentModificationException`[^2]。 - **HashMap的无限循环风险** 并发扩容可能引发死循环(JDK8已优化)。 --- #### 五、如何选择线程安全集合? | 场景 | 推荐类 | 原因 | |------|--------|------| | 高频读写Map | ConcurrentHashMap | 分段锁/CAS平衡性能与安全 | | 读多写少List | CopyOnWriteArrayList | 写时复制避免锁竞争 | | 任务队列 | LinkedBlockingQueue | 阻塞机制适合生产者-消费者模型 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值