HashMap HashTable ConcurrentHashmap

HashMap

小知识点

  • Entry的结构
    static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
        //..............
    }
    //hash 是key对应的hash值,hash算法由hashmap本身产生 用于在bucket
    //table中定位存放的bucket,key 为null时 hash值为0.这个hash生成的
    //hash值与当前的桶多少(table的size)有关系,每次移动是否需要rehash跟。
  • 默认大小16

  • 负载因子0.75

  • hashmap 可以存储null

  • threshold阈值,如果超过该数值,则扩大capacity到某个2的n次方,当然会有最大限制 MAXIMUM_CAPACITY = 1 << 30,此时数据会进行移动比较耗时。

  • put方法 如果已经存在对应的key 会返回该key之前对应的value。

  • JDK1.8增加了红黑树部分 当链表长度大于8将转化为红黑树。

  • hashmap的bucket是一个数组,放入以及取元素是是根据key的hash值与当前数组长度(必须是2的次方)-1进行与运算,找到bucket后for循环检查链表(Entry里有个next 通过next实现链表)

    static int indexFor(int h, int length) {
        return h & (length-1);
    }
  • 重新调整HashMap大小时的多线程问题
    如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在LinkedList中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在LinkedList的尾部,而是放在头部,如果线程1 将table[1]的数据往table[2]移动 而线程2 将数据网table[1]移动 则陷入了死循环。

  • 快速失败
    如果在使用迭代器的过程中有其他线程修改了 map,那么将抛出ConcurrentModificationException,这就是所谓 fail-fast 策略。这一策略在源码中的实现是通过 modCount 域, modCount 顾名思义就是修改次数,对HashMap 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount 如果发现此值不等于modCount就会抛出异常。

相关方法

  • AbstractMap.remove()
    返回删除成功后的值,不存在返回null,另外删除了null,返回也是null。

  • inflateTable扩大表
    将表大小扩张至2的n次方

疑问

  • 关于hashmap中比较key 是否相等的判断:

    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {}
    //不明白为什么不直接用equals,为啥要用==  ,首先==是比较地址 如果地址
    //相同 那么equals返回肯定是true  那么直接比较equals就可以了 为什么要比
    //较==?  是因为使用==可以节省计算?比较快速?
  • hashmap何时进行rehash?即initHashSeedAsNeeded何时返回true?

HashTable

小知识点

-加载因子和hashmap一致0.75 ,但是初始大小为11 不是hashmap的(16)
- key、value不能为null
- 每次扩容新容量=旧容量 * 2 + 1
- hashtable每次同步执行的时候都要锁住整个结构 锁整个表
- 如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以效率低。

ConcurrentHashMap

介绍

ConcurrentHashMap融合了hashtable和hashmap二者的优势。
ConcurrentHashMap的工作机制,通过把整个Map分为N个Segment(每个segment类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。
这里写图片描述

  • 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁.

小知识点

hashMap hashTable区别

  • 第一:HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。
    第二:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。而当HashTable遇到null时,他会直接抛出NullPointerException异常信息。
    第三:Hashtable的方法是同步的,而HashMap的方法不是。

参考

http://ifeve.com/concurrenthashmap/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值