数据结构: 数组+链表+红黑树
解决哈希冲突的主要方法:
- 开放定址法(线性探查法、线性补偿探测法(
- 拉链法(单链表)
它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap
为什么说hashmap是线程不安全的
如果线程A和线程B同时进行put操作,刚好这两条不同的数据hash值一样,并且该位置数据为null,接下来线程A、B本应该都会进入源码631行进行执行操作,如果此时,线程A进入后还未进行数据插入时挂起了,没有获取到CUP时间片,而线程B正常执行,从而B正常插入数据,放入一个元素,然后执行完了B走了,此时轮到线程A获取CPU时间片,在挂起前已经执行了源码630行,线程A将不用再进行hash判断了,而是直接执行源码631行。杯具来了:线程A会把线程B插入的数据给覆盖,发生线程不安全。针对这个情况怎么处理呢,可以直接对整个方法加锁,用synchronized,但性能损耗太大。官方推荐使用ConcurrentHashMap,采用分段锁机制,即避免了线程不安全,也极大照顾了性能损耗
如果确定只装载100个元素,new HashMap(?)多少是最佳的
重点关注tableSizeFor(initialCapacity),这才是真正的容量,结果是返回一个不小于传入参数并且最近的一个2的n次方的值,扩容阈值threshold = size * 0.75,言外之意就是当元素put到第96个时,就会再次进行resize()方法,而resize()方法是非常耗时间的,结合我们实际情况进行一次resize()方法只为了多放4个元素,这样的损耗显然是不适合的;所以,综上所述,个人觉得初始化最好的应该是256
属性
- loadfactor:负载因子,默认为0.75
- threshold:所能容乃的键值对的临界值=数组长度 * 负载因子
- modcount:记录hashmap内部结构发生变化的次数
更多技术博客、答疑、交流,欢迎关注我的微信公众号:寅贝勒