HashMap<br>线程不安全
1.7数组+链表
扩容(resize)<br>rehash
扩容:创建一个新的数组,长度是原来的两倍<br>
rehash(长度不同,hash规则不同):重新计算hash值,将原数据重新插入到新数组中
头插法:扩容时会有死循环的可能,新值被认为更有几率被查询
1.8数组+链表+红黑树
扩容(resize)<br>rehash<br>
扩容:创建一个新的数组,长度是原来的两倍
rehash(长度不同,hash规则不同):重新计算hash值,将原数据重新插入到新数组中
尾插法:不会产生死循环,但多线程条件下,会存在put的值被覆盖的可能
参数
默认初始化容量(数组长度)16
2的整数次幂,为了实现数组的均匀分布
默认负载因子:0.75
树形化阈值(1.8以后):8
即当链表的长度大于8的时候,会将链表转为红黑树,优化查询效率
树形化最小容量(1.8以后):64
HashMap数组的容量大于等于64时,将链表转化成红黑树<br>
equals&hashCode
为了保证相同的对象返回相同的hash值,不同的对象返回不同的hash值<br>
ConcurrentHashMap<br>线程安全,效率高
快速失败(fast-fail):当使用迭代器遍历时,如果数组长度发生变化,会抛出异常
1.7版本(segment分段锁)
结构不变:数组+链表<br>
segmen继承于ReentrantLock,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发<br>
每个segment(段)都可以被当作一个HashMap
使用volatile修饰了entry,保证了线程间的可见性,防止指令重排序
将数组分为多个(segment)段,每个段包含几个entryList,使用时对相应的segment上锁,不会影响其他的segment
get方法不需要加锁,因为加了volatile关键字,保证了每次读到的都是最新的数据
链表限制了查询的速度,如果链表很长,效率也不是很高
1.8版本(synchronise锁+CAS)
采用CAS + synchronized 来保证并发安全性
用Node替代HashEntry,但作用不变
把值和next采用了volatile去修饰,保证了可见性<br>
引入红黑树,当链表长度大于一定值的时候(默认8)会转换成红黑树
put的时候首先尝试CAS写入,失败则自旋<br>判断是否需要扩容,是否需要转换成红黑树<br>如果都不满足,使用sychronized锁
HashTable<br>继承Dictionay<br>线程安全,效率低
对数据的操作都会上锁,效率低不用的根本原因
不允许键或值为null,因为安全失败机制,使用空值时,无法判断对应的key是不存在还是为null<br>
安全失败(safe-fail):使用迭代器读取数据时,数组长度变化时,不会报异常,这会使读到的值不一定是最新的值<br>
迭代器也为安全失败的
初始容量为11,扩容为二倍原数组大小+1<br>
synchronizedMap<br>(同步Map)
SynchronizedMap内部维护了一个普通对象Map,还有排斥锁mutex
当创建处SynchronizedMap的时候,所有对它的操作都是上了锁的