「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」
list
- 常用方法 add ,remove , contains
- 允许重复元素
arrayList
- 采用数组实现
- 数组集合,自动扩容0.5倍 ,插入慢,索引快
- 线程不安全
Vector
- 数组集合,底层采用数组实现
- 自动扩容1倍
- 线程安全
LinkedList
链表集合,无容量限制,插入快,索引慢
map
- k - v 表,
- k不能重复
- 常用方法 get , put ,containsKey
ArrayMap
- 采用双数组实现
- 非线程安全
- 节约内存
hashMap
- HashMap 底层是数组+链表(jdk1.8是数组+链表/红黑树),HashMap可能也是应用最多的数据结构了
- 非线程安全
- 由于hash的存在,输出与输入顺序不一致,也常被称为无序表。
hashMap什么时候链表会进化为红黑树
- 链表长度超过8,并且容量大于64,会转化为红黑树
- 链表长度小于6,退化为链表。
hashMap为什么大小总是2的n方
hashmap的初始值是16,即2的4次方,之后的每次扩容都是两倍扩容,为什么呢?两条与运算比取模高效;
- 如果往hashmap中存放数据,我们首先得保证它能够尽量均匀分布,为了保证能够均匀分布,我们可能会想到用取模的方式去实现,如果用传统的‘%’方式来实现效率不高,当大小(length)总为2的n次方时,h&(length-1)运算等价于对length取模,也就是h%lenth,但是&比%具有更高的效率,同时也减少了hash碰撞。
- 和h&(length-1)相关,当容量大小(n)为2的n次方时,n-1 的二进制的后几位全是1,在h为随机数的情况下,与(n-1)进行与操作时,会分布的更均匀,想一想,如果n-1的二进制数是1110,当尾数为0时,与出来的值尾数永远为0,那么0001,1001,1101等尾数为1的位置就永远不可能被entry占用,就造成了空间浪费。
为什么用与运算取代取余运算
取余运算是通过多次循环除法运算实现的,效率远低于与运算。 假设是2381除以7。2381,二进制为1001 0100 11017,
- 二进制为111用2381的最高位1001减去111,得10。相当于2381-7*256 = 589
- 589 = 刚才的答案10+之前没用过的右边01001101 = 1001001101
- 再次重复刚才的过程589的最高位1001减去111,得10。相当于589-7*64 = 141141 = 刚才的答案10+之前没用过的右边001101 = 10001101。。。。。
- 如此循环,最后,当被除数剩1时即为余数
如何保证空间大小是2的幂次
- 之所以在开始移位前先将容量-1,是为了避免给定容量已经是8,16这样2的幂时,不减一直接移位会导致得到的结果比预期大。比如预期16得到应该是16,直接移位的话会得到32。
- 由于hashMap的最大大小只能是1<<<32位,所以,不需要继续右移32位了。
LinkedHashMap
- 双向链表实现
- 输入与输出顺序一致,有序
- 非线程安全
hashTable
线程安全,过缺点:因为采用synchronized保证同步,每次都会锁住整个map,所以高并发线程在争夺同一把锁的时候性能急剧下降
TreeMap
- 是一个红黑树版本的map,实现了NavigableMap<K,V>并且NavigableMap又继承了SortedMap<K,V>类,SortedMap接口有一个Comparator<? super K> comparator();比较器,所以TreeMap是支持比较排序的
- 内部的key是有序的
ConcurrentHashMap
底层也是HashMap,同时保证了线程安全,与HashTable不同的ConcurrentHashMap采用分段锁思想,抛弃了使用synchronized修饰操作方法的同步方式。
都知道HashTable效率低下的原因是因为整个容器只有一把锁,多线程争抢同一把锁导致。 ConcurrentHashMap分段锁指得是将数据分成一个个的Segment<K,V>,每个Segment又继承ReentrantLock,这样一个map容器就会有多个Lock,每个Lock锁不同的数据段,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
1.7与1.8的区别:
- 因为底层是HashMap,1.8之后也变成了数组+链表/红黑树。
- 1.8之后放弃了分段锁,采用了synchronized+CAS来保证并发。
为何放弃分段锁:
- 我认为主要是1.8对synchronized进行了优化(偏向锁、轻量级锁、自旋锁、自适宜自旋)
- 加入多个分段锁浪费内存空间。
- 生产环境中,map在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待
set集合
- 元素不能重复
HashSet
- HashSet 基于HashMap实现,利用Map的key不能重复来实现Set的元素唯一性
LinkedHashSet
- 采用双向链表和hashMap实现
stack栈
- 采用Vector实现
- 线程安全
- 后进先出
Queue
- 队列
- 先进先出
- add 超出容量会跑出异常,offer不会。
Deque
double end queue , 双向操作嘟列
ArrayDeque
- 数组实现的双向操作队列
- 非线程安全
LinkedBlockingDeque
- 线程安全队列
- ReentrainLock实现等待
- 链表实现的阻塞双头队列
ArrayBlockingQueue
- 线程安全
- ReentrainLock实现等待
- 数组实现的阻塞双头队列