线程不安全的集合

集合概述

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 ,使⽤跳表的数据结构进⾏快速查找
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值