java常见集合

集合

  1. 谈谈对集合的理解

集合是java.util包中的,是一种数据存储容器

分为Collection接口(value)和Map接口(key-value)

Collection:

List接口:有序可重复的

Set接口:无序不可重复的

Map接口:无序不可重复的

List接口:

ArrayList: 有序可重复----实现RandomAccess接口,实现下标查询

底层使用Object数组,初始化容量为10,扩容到1.5倍。

特点:基于数组,查询效率快,插入删除效率慢

LinkedList:基于双向链表;有序;查找速度慢,添加和删除效率快

Vector:线程安全,有大量的synchronized线程安全的方法;

  底层是object数组,初始容量为10,扩容到2倍

Set接口:

HashSet:底层使用HashMap,以key为主,value为空对象

LinkedHashSet:底层使用LinkedHashMap,有序

TreeHashSet:底层使用TreeMap,可自动排序,实现Compareator,Compareable接口

Map接口:key-value键值对为主,无序不可重复

HashMap: key-value可以为空;底层使用数据+链表+红黑树,提高搜索效率

无参为16,有参则根据原有容量*0.75来扩容到原来的二倍

数组长度大于64,链表长度大于8则转为红黑树

LinkedHashMap: 底层是单向链表;继承于HashMap;有序

TreeMap:底层红黑树;可以自动排序;实现Compareable(compareTo()方法)和Compareactor(compare()方法)接口

HashTable:key,value不允许为空,为空发生空指针异常

线程安全;底层数组+链表,无参:11 有参扩容到2倍+1

  1. 集合中哪些线程是安全的

CopyOnWirteArrayList:

Java.util. concurrent并发包下的线程安全的List集合,兼顾安全和性能

在线程安全的情况下代替vector和ArrayList.进行增删改操作时,通过ReentrantLock加锁,复制出来一个新数组的方式来实现线程安全,用于读多写少的情况。

对原有的数据进行一次复制,将修改的内容写入新副本,写完后,再将新数据代替原有数据,保证写操作不会影响读操作。只能保证数据的最终一致性,但不保证数据实时一致性。增删改为新数组,读写为原数组。

缺点:由于每次都要创建一个新数组,消耗内存。

 只能保证数据最终一致性,不能保证数据实时性。

ConcurrentHashMap:

基于线程安全的HashMap,底层采用分段的数组+链表+红黑树;将数据分为一段一段的存储,给每一段数据分配一把锁,当一个线程占用这个数据段的锁时,其他段也可以被其他线程访问。

Jdk1.7: 一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和HashMap类似,是一种数组和链表结构,一个segment包含一个HashEntity数组,每个Entity是一个链表结构的元素,一个segment守护一个Entity数组的全部元素

Jdk1.8:取消了segment分段锁,采用CAS和synchronized来保证并发安全。Synchronized只锁定当前链表或红黑二叉树的首节点,提高了效率。

    

  1. HashMap在多线程环境中存在线程安全问题,一般如何处理

  1. 使用Collections.synchronizedMap(Map)创建线程安全的map集合
  2. 使用Hashtable
  3. 使用ConcurrentHashMap

SynchronizedMap内部维护了一个普通的Map对象,还有排斥锁mutex,若构造方法中没有传入mutex,则排他锁为当前对象,若构造方法有则采用传入的对象做锁

Hashtable内部的方法全部采用Synchronized进行加锁,封锁粒度过大且为重量级锁。

ConcurrentHashMap:

   Jdk1.7:数组+链表;采用sgement分段锁进行处理,sgement数组中包含了hashEntry数组,保证一个线程访问的同时,其他线程可以访问其他的分段数据。此外,为value添加了volatile(可见性,禁止指令重排,无原子性),当进行put操作时,先通过sagment中的(table-1)&hash(key)>>>低16位得到index,先尝试获取锁,若获取不到则代表其他线程在竞争,从而进行自旋,若自旋失败进行锁升级,从而进行赋值。其get操作就是通过key和hash获取指定位置进行拿值即可。

Jdk1.8 数组+链表+红黑树,采用synchronized+CAS保证线程安全性。底层可是给value加volatile保证其他线程拿到的value是最新的。在put操作时,通过一系列的运算获取index下标,若下标为null,则代表可以进行添加,先通过CAS尝试写入,若写入失败进行自旋,若自旋次数超过指定此时后,通过synchronized锁进行写入,其他线程等待。若不为空,则判断key是否一致,若一致则覆盖,若不一致,则进行向链表尾部添加数据。(synchronized只在链表首部和红黑树首部进行加锁)

   

4.  fail-fast和fail-safe的理解

fail-fast(快速失败):java集合中的一种机制,适用于hashmap,在迭代器遍历一个集合对象时,如果遍历过程中对象的内容进行了修改(添加,修改,删除),从而抛出ConcurrentModification Exception.

原理:迭代器遍历时直接访问集合中的元素,并在遍历过程中使用一个modcount变量。

   集合在遍历期间若内容发生变化,就改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,先检查modCount是否为expectedmodCount值,是的话返回遍历,否则抛出异常,终止遍历。

由于集合元素发生改变时,若将modCount设置为expectedmodCount,则不抛出异常,因此,不能依赖是否抛出异常而进行并发操作,该异常仅用于检测并发修改的bug

Fail-safe(安全失败):java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

   原理:由于迭代时是对原有集合的拷贝进行遍历,所以在遍历过程中对原有集合所作的修改并不能被迭代器检测到,从而不引发fail-fast.

   缺点:在迭代器遍历拷贝集合时,无法知道原集合的修改

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大西瓜写java、C#、.NET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值