Java-Map

 

HashMap

HashMap(Java以前):数组+链表

最坏的情况的是从O(1)变成

 

hashMap(java8及以后):数组+链表+红黑树

 

HashMap:put方法的逻辑

1.如果HashMap未被初始化过,则初始化

2.对key求Hash值,然后再计算下标

3.如果没有碰撞,直接放入桶中

4.如果碰撞了,以链表的方式链表到后面

5.如果链表长度超过阀值,就把链表转成红黑树

6.如果链表长度低于6,就把红黑树转回链表

7.如果节点已经存在就替换旧值

8.如果桶装满了(容量16*加载因子0.75),就需要resize(扩容2倍后重排)

 

HashMap:如何有效减少碰撞

扰动函数:促使位置分布均匀,减少碰撞几率

使用final对象,并采用合适的equals()和hashCode方法

 

 

HashMap:扩容的问题

多线程环境下,调整大小会存放条件竞争,容易造成死锁

rehashing是一个比较耗时的过程

 

Hashtable

早期Java类库提供的哈希表的实现

线程安全:涉及到修改Hhashtable的方法,使用synchronized修饰

串行化的方式运行,性能较差

 

如何优化Hashtable

通过锁细粒度化,将整锁拆解成多个锁进行优化

 

ConcurrentHashMap

ConcurrentHashMap:put方法的逻辑

1.判断Node[]数组是否初始化,没有则进行初始化操作

2.通过hash定位数组的索引坐标,是否有Node节点,如果没有则使用CAS进行添加(链表的头节点),添加失败则进入下次循环。

3.检查到内部正在扩容,就帮助它一块扩容。

4.如果f!=null,则使用synchronize锁住f元素(链表/红黑树二叉树的头元素)

   4.1 如果是Node(链表结构)则执行链表的添加操作

   4.2 如果是TreeNode(树形结构)则执行树添加操作

5. 判断链表长度已经达到临界值8,当然这个8是默认值,大家也可以去做调整,当节点数超过这个值就需要吧链表转换为数结构

 

 

CoucurrentHashMap总结:比起Segment,锁拆得更细

首先使用无锁操作CAS插入头节点,失败则循环重试

若头节点已存在,则尝试获取头结点的同步锁,在进行操作

 

三者的区别

HashMap线程不安全,数组+链表+红黑树

Hashtable线程安全,锁住整个对象,数组+链表

ConcurrentHashMap线程安全,CAS+同步锁,数组+链表+红黑树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值