Map 接口定义的集合又称为查找表,用于存储所谓“key-value"映射对。Key可以看成是Value 的索引,作为key的对象在集合中不可重复。其中键是唯一的,值可以不唯一,一个键可以指向多个值。
Map接口的实现类主要包括以下几种:
- HashMap
- TreeMap
- LinkedHashMap
- HashTable
- ConcurrentHashMap
下面就针对以上的几种常用的实现类具体进行一下简介。
1.HashMap
基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射。HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改。HashMap是非synchronized,所以HashMap很快。
2.TreeMap
TreeMap类不仅实现了Map接口,还实现了java.util.SortMap接口,因此集合中的映射关系具有一定的顺序.但是在添加,删除,和定位映射关系上,TreeMap类比HashMap类的性能差一些.TreeMap类实现的Map集合中的映射关系是根据键值对象按一定的顺序排列的.因此不允许键对象是null。
3.LinkedHashMap
LinkedHashMap是HashMap的子类,但是内部还有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于双向链表中。LinkedHashMap支持两种顺序插入顺序 、 访问顺序。
4.HashTable
Hashtable是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。Hashtable是JDK1.0引入的类,是线程安全的,能用于多线程环境中。
Hashtable实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
5.ConcurrentHashMap
concurrenthashmap是由Segment数组结构和HahEntry数组结构组成.Segment是一种可重入锁ReentrantLock,扮演锁的角色。HashEntry用于存储键值对数据。一个concurrenthashmap里包含一个Segment数组。Segment的结构和Hashmap类似,是一种数组和链表结构,一个Segment包含一个HashEntry数组,每个HashEntry是一个链表结构的元素,每个Segment守护着一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得对应的Segment。
问题:ConcurrentHashMap和HashTable的区别:
hashtable(同一把锁): 使用synchronized来保证线程安全,但效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用put添加元素,另一个线程不能使用put添加元素,也不能使用get,竞争会越来越激烈效率越低。
concurrenthashmap(分段锁):(锁分段技术)每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。
首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。