java Map学习

1 篇文章 0 订阅

几个关于map的问题

1.map有哪些,特点和使用场景?(只知道hashmap,hashtable是不够的)

2.哪些方面会影响hashmap的性能?

3.线程安全的map有哪些,concurrenthashmap是如何实现线程安全的(jdk1.8大不同)?

 

Map实现类用于保存具有映射关系的数据。Map保存的每项数据都是key-value对,也就是由key和value两个值组成。Map里的key是不可重复的,key用户标识集合里的每项数据。

 

1.HashMap

HashMap将Entry对象存储在一个数组中,并通过哈希表来实现对Entry的快速访问:

(发生冲突)

HashMap最多只允许一条记录的键为Null(多条会覆盖)。允许多条记录的值为 Null。非同步的。

线程不安全的Map,方法上都没有synchronize关键字修饰。

 

1.1 LinkedHashMap

LinkedHashMap它的特点主要在于linked,带有这个字眼的就表示底层用的是链表来进行的存储。

相对于其他的无序的map实现类,还有像TreeMap这样的排序类,linkedHashMap最大的特点在于有序,但是它的有序主要体现在先进先出FIFIO上。

LinkedHashMap主要依靠双向链表和hash表来实现的。

 

1.2 ConcurrentHashMap

ConcurrentHashMap是HashMap的线程安全版(自JDK1.5引入),提供比Hashtable更高效的并发性能。

 

jdk1.7

Hashtable 在进行读写操作时会锁住整个Entry数组,这就导致数据越多性能越差。

而ConcurrentHashMap使用分离锁(分段锁)的思路解决并发性能,其将 Entry数组拆分至16个Segment中,以哈希算法决定Entry应该存储在哪个Segment。这样就可以实现在写操作时只对一个Segment 加锁,大幅提升了并发写的性能。

在进行读操作时,ConcurrentHashMap在绝大部分情况下都不需要加锁,其Entry中的value是volatile(不稳定 易变)的,这保证了value被修改时的线程可见性,无需加锁便能实现线程安全的读操作。

jdk1.8

1.8的实现已经抛弃了Segment分段锁机制,利用CAS+Synchronized来保证并发更新的安全,底层采用数组+链表+红黑树的存储结构。

2.HashTable

Hashtable 可以说是HashMap的前身(Hashtable自JDK1.0就存在,而HashMap乃至整个Map接口都是JDK1.2引入的新特性),其实现思 路与HashMap几乎完全一样,都是通过数组存储Entry,以key的哈希值计算Entry在数组中的index,用拉链法解决哈希冲突。

二者最大的不同在于,Hashtable是线程安全的,其提供的方法几乎都是同步的,有synchronize关键字修饰。

(现在不推荐使用)。

 

HashMap vs Hashtable vs ConcurrentHashMap

  • 三者在数据存储层面的机制原理基本一致
  • HashMap不是线程安全的,多线程环境下除了不能保证数据一致性之外,还有可能在rehash阶段引发Entry链表成环,导致死循环
  • Hashtable是线程安全的,能保证绝对的数据一致性,但性能是问题,并发线程越多,性能越差
  • ConcurrentHashMap 也是线程安全的,使用分离锁和volatile等方法极大地提升了读写性能,同时也能保证在绝大部分情况下的数据一致性。但其不能保证绝对的数据一致性, 在一个线程向Map中加入Entry的操作没有完全完成之前,其他线程有可能读不到新加入的Entry

 

3.TreeMap

TreeMap是基于红黑树实现的Map结构,其Entry类拥有到左/右叶子节点和父节点的引用,同时还记录了自己的颜色:

static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left = null;
        Entry<K,V> right = null;
        Entry<K,V> parent;
        boolean color = BLACK;
}

 

红黑树实际是一种算法复杂但高效的平衡二叉树,具备二叉树的基本性质,即任何节点的值大于其左叶子节点,小于其右叶子节点,利用这种特性,TreeMap能够实现Entry的排序和快速查找。

关于红黑树的具体介绍,可以参考这篇文章,非常详细:http://blog.csdn.net/chenssy/article/details/26668941

TreeMap的Entry是有序的,所以提供了一系列方便的功能,比如获取以升序或降序排列的KeySet(EntrySet)、获取在指定key(Entry)之前/之后的key(Entry)等等。适合需要对key进行有序操作的场景。

能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。

4.ConcurrentSkipListMap

ConcurrentSkipListMap同样能够提供有序的Entry排列,但其实现原理与TreeMap不同,是基于跳表(SkipList)的:

如上图所示,ConcurrentSkipListMap由一个多级链表实现,底层链上拥有所有元素,逐级上升的过程中每个链的元素数递减。在查找时从顶层链出发,按先右后下的优先级进行查找,从而实现快速寻址。

static class Index<K,V> {
        final Node<K,V> node;
        final Index<K,V> down;//下引用
        volatile Index<K,V> right;//右引用
}

与TreeMap不同,ConcurrentSkipListMap在进行插入、删除等操作时,只需要修改影响到的节点的右引用,而右引用又是volatile的,所以ConcurrentSkipListMap是线程安全的。但ConcurrentSkipListMap与ConcurrentHashMap一样,不能保证数据的绝对一致性,在某些情况下有可能无法读到正在被插入的数据

 

TreeMap vs ConcurrentSkipListMap

  • 二者都能够提供有序的Entry集合
  • 二者的性能相近,查找时间复杂度都是O(logN)
  • ConcurrentSkipListMap会占用更多的内存空间
  • ConcurrentSkipListMap是线程安全的,TreeMap不是

 

5.WeakHashMap

weakHashMap它是一个“弱键”,它的Key值和Value都可以是null,而且其Map中如果这个Key值指向的对象没被使用,此时触发了GC,该对象就会被回收掉的。其原理主要是使用的WeakReference和ReferenceQueue实现的,其key就是weakReference,而ReferenceQueue中保存了被回收的 Key-Value。

如果当其中一个Key-Value不再使用被回收时,就将其加入ReferenceQueue队列中。当下次再次调用该WeakHashMap时,就会去更新该map,比如ReferenceQueue中的key-value,将其中包含的key-value全部删除掉。这就是所谓的“自动删除”。
 

 

 

参考文章:
JAVA集合框架中的常用集合及其特点、适用场景、实现原理简介链接:https://www.jianshu.com/p/b54f1df33f84
Java map 详解 - 用法、遍历、排序、常用API等  https://www.cnblogs.com/lzq198754/p/5780165.html

由浅入深理解java集合(一)——集合框架 Collection、Map https://www.jianshu.com/p/589d58033841

深入浅出ConcurrentHashMap1.8 https://www.jianshu.com/p/c0642afe03e0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值