Collection详解:
HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
HashMap和Hashtable的区别。
ArrayList、LinkedList、Vector的区别。
HashMap和ConcurrentHashMap的区别。
HashMap和LinkedHashMap的区别。
HashMap是线程安全的吗。
ConcurrentHashMap是怎么实现线程安全的。

分类:
可以按照接口,实现,算法 三个方面对集合框架中的数据结构进行分类。
**接口:**Collection,List,Map 组成了集合框架中所有具体实现类的接口,他们定义了子类必须实现的方法。比如向集合添加元素,会用到Collection中定义的add()方法。

**实现:**实现上述3个接口的类,都被称作集合框架,实际上就是数据结构,比如LinkedList,TreeSet等

算法: 集合框架提供了很多可以直接调用的算法,比如求最大最小值,排序,填充等

ArrayList,LinkedList,Vector对比:
ArrayList和LinkedList都是不同步的,都不是线程安全,
Arraylist底层数据结构是Object数组,LinkedList底层使用双向循环链表
ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置影响
LinkedList采用链表存储,所以插入,删除元素时间复杂度不受元素位置影响,
LinkedList不支持随机元素访问,而ArrayList实现了RandmoAccess接口,所以有随机访问功能,
ArrayList空间的浪费主要体现在List列表会在结尾预留一定的容量空间,LinkedList的空间浪费体现在它每个元素都要存储前继后继
Vector类所有方法都是同步的,可以由两个线程安全访问一个vector对象,底层是Object数组

HashMap的底层实现:
1.8之前HashMap由数组+链表组成的(链表散列)数组是HashMap的主体,链表是为了解决哈希冲突而存在的(HashMap采用拉链地址法解决冲突),如果定位的数组位置不含有链表,对于添加操作,时间复杂度为O(1),因为最新的Entry会插入到链表头部,简单改变引用链即可,而对于查找操作,则需要找到位置,然后通过遍历链表

1.8之后,在解决哈希冲突的时候有了很大变化,当链表长度大于阈值(默认8),将链表转化为红黑树,已减少搜索时间
TreeMap,TreeSet以及1.8之后的HashMap底层都变为了红黑树,红黑树是为了解决二叉查找树的缺陷,在某些情况下会退化成一个线性结构

HashMap和HashTable的区别:
hashMap是非线程安全的,HashTable是线程安全的,HashTable内部方法都基本经过了synchronized修饰
效率:HashMap要比HashTable效率高
HashMap中 null可以作为键,但只能有一个,但多个键所对应的值可以为null。
HashTable中put进的键值只要有一个null,则直接抛出NullPointException
初始容量大小和每次扩容大小不同:如果不指定初始值,HashTable默认大小为11,每次扩容变为原来的2n+1。HashMap默认初始化大小为16,每次扩容变为原先的2倍。如果创建时给定了容量初始值,HashTable会直接使用你给的初始值,但HashMap会将其扩充为2的幂次方大小。
1.8后HashMap在解决哈希冲突时有了变化,HashTable没有这样的机制

HashMap的长度为什么是2的幂次方大小:
为了能让HashMap存取高效,尽量减少碰撞,数据平均分配,
“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。

HashMap 与HashSet的区别
HashMap实现了Map接口,HashSet实现了Set接口
存储键值对,仅存储对象
put方法向map中添加元素,add方法向set中添加元素
HashMap使用key计算hashCode,
HashSet使用成员对象来计算hashCode,对于两个对象hashCode可能相等,所以用equals方法用来判断对象的相等性,如果连个对象不同的话,那么返回false。
对于两个对象hashCode可能相同,所以要用equals来判断对象的相等性(HashSet equals相等则无法放入HashSet)

ConcurrentHashMap和HashTable区别:
1.7 ConcurrentHashMap底层采用分段数组+链表的实现
1.8 采用 和HashMap1.8一样的结构,数据+链表/红黑二叉树,
1.8之前,HashMap的底层数据结构类似都是采用数组+链表的形式,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。

1.7的时候,ConcurrentHashMap(分段锁)对整个桶数组进行了分割分段,把每一把锁只锁容器其中一个部分,多线程访问容器里不同的数据段的数据,就不会存在锁竞争,提高并发访问率。默认分配了16个锁,比HashTable效率提高16倍
JavaCore-Collection详解
Segment实现了ReentrantLock,所以Segment是一种可重入锁,扮演锁的角色。

到了1.8时候摈弃了Segment的概念,直接使用Node数据+链表+红黑树的数据结构来实现,并发控制使用了synchronized和CAS操作,看起来就像是优化过且线程安全的HashMap
JavaCore-Collection详解
CAS和synchronized来保证并发安全,synchronized值锁定当前链表or红黑二叉树的首节点,这样只要hash不冲突,就不会发生并发安全,效率提升n倍

HashTable使用同一把锁,synchronized来保证线程安全,效率分厂低下,当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞or轮循状态,

结合框架底层数据结构总结:
Collection:
List
ArrayList: Object 数组
Vector: Object数组
LinkedList:双向循环链表

Set
HashSet(无序,唯一):基于HashMap实现的,底层采用HashMap来保存元素
LinkedHashSet:继承自HashSet,内部是通过LinkedHashMap来实现的。
TreeSet(有序,唯一):红黑树

Map:
HashMao:1.8之前 数据+链表 数组是HashMap的主体,链表为了解决哈希冲突而存在,1.8之后,在解决哈希出图有了较大变化,当链表长度大于阈值(默认8),将链表转化为红黑树,以减少搜索时间。
JavaCore-Collection详解

LinkedHashMap:
继承自HashMap,底层仍然是基于拉链散列结构由数组和链表or红黑树组成,在此基础上,LinkedHashMap在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序,同时通过链表进行相应操作。实现访问顺序相关逻辑。
JavaCore-Collection详解
HashTable:数组+链表组成,数组是HashMap的主体,链表主要是为了解决哈希冲突而存在的

TreeMap:红黑树

CAS技术简单介绍,CompareAndSwap, 即比较并替换,实现并发算法时候常用的一种技术
思想:三个参数,一个当前内存值V,旧的预期值A,即将更新的值B,当且仅当预期值A和内存值A相同时,将内存值修改为B并且返回true,否则什么都不做,并返回false

缺点:
存在一个ABA问题:
如果变量V初次读取的时候是A,并且在准备赋值的时候任然检查到它是A,并不一定是没有被其他线程改过,如果这段期间曾将被改成B,然后又改回A,那CAS操作就会误以为它原本根本没有被修改过,针对这种情况,java并发包中提供了一个带有标记的原子引用类AtomicStampedReference,它可以通过控制变量值的版本来确保CAS的正确性

相关文章: