关于List、Set、Map接口:
List:
- 继承Collection接口;有序集合,允许重复元素。
- 这个接口的用户可以精确地控制列表中每个元素插入的位置。
- 用户可以通过其整数索引(在列表中的位置)访问元素,并在列表中搜索元素。
- 提供了一个特殊的迭代器,称为ListIterator,它允许插入和替换元素,除了迭代器接口提供的正常操作外,还提供双向访问。
Set:
- 继承Collection接口;无序集合,不允许重复元素,且最多有一个null值。
Map:
- key_value键值对;不允许重复元素。
- Map不是collection的子接口或者实现类。Map是一个接口。
- Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
关于ArrayList、LinkedList、Vector:
ArrayList:
- 实现List接口;允许null值,这个类大致相当于Vector,只是它是不同步的。
- 在内存中分配连续的空间,在遍历元素和随机访问元素时效率高。
LinkedList:
- List和Decode接口的双链表实现;允许null值,与ArrayList类似,不同步。
- 链表存储方式,在插入,删除元素时效率高,提供额外的addFist(),addlast(),removeFirst(),removeLast(),索引到列表中的操作将从开头
- 结尾遍历列表,以较接近指定索引为准。
Vector:
- 实现可扩展的对象数组
- Vector中最后一个元素后面的任何数组元素都为null。
- 存储矢量分量的数组缓冲区, 矢量的容量是这个数组缓冲区的长度,并且至少足够大以包含所有矢量的元素。
关于HashMap、HashSet:
HashMap:
- 继承Map接口,实现了哈希表,允许null,非同步。
- 哈希表结构其实就是数组+链表;
- 在JDK1.8中规定:当链表长度大于8时,链表长度就转换为红黑树,大大提高了查找效率。
HashSet:
继承Set接口,实现了由哈希表支持的Set接口,只能放入一个null元素,不同步。实际上是一个HashMap实例。
关于HashMap、HashTable和CurrentHashMap区别
HashMap
- 以前是底层数组+链表实现,可以存储null键和null值,线程不安全。
- jdk1.8后,数组+链表+红黑树
- 初始size为16,扩容:newsize = oldsize*2
- 在多线程环境下,使用hashmap进行map操作会引起死循环,导致cpu利用率解决100%,所以并发下不能使用hashmap。
HashTable
- 底层数组+链表实现,key还是value都不能为null,
- 线程安全,在修改数据时锁住整个HashTable,效率低,使用synchronize修饰。
- 初始size为11,扩容:newsize = oldsize*2+1
- 多线程访问时,只要有一个线程访问或操作该对象,其他线程只能阻塞,并发性能非常差。
CurrentHashMap
- jdk1.7 采用数组+segment+ 分段锁来实现
分段锁技术:将数据分成一段一段的存储,然后每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段数据也能被其他线程访问,能够实现真正并发访问。
缺点:hash的过程要比普通hashmap要长。
-
jdk1.8 采用数组+链表+红黑树,内部大量使用CAS操作,CAS时一种乐观锁
悲观锁:将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。
乐观锁:通过方式不加锁处理资源,性能优于悲观锁。 -
jdk1.8 彻底放弃segment 而采用node,不再使用分段锁。
-
线程安全
jdk1.7采用segment分段锁机制,segment继承自ReetrantLock
jdk1.8 采用CAS + synchronized,是对hashtable进行优化,将锁细粒化到每个table的每个元素,来提升并发性能。 -
链表节点数量大于8时,链表转换为红黑树
-
时间复杂度:从遍历链表O(n),变成遍历红黑树O(logN).