JAVA中常见的容器类HashMap,TreeMap,HashTable,LinkedHashMap,ConcurrentHashMap

a、HashMap

HaspMap在jdk1.7采用数组+链表的数据结构,随着数据存储量的增大,hash碰撞会越来越频繁。意味着链表的长度会越来越长,查询的效率不断的降低,在插入时首先根据hash值的低n位,找到数组下标的位置,然后进行key的判重,没有重复则在表头插入,取值也是首先计算key的hash值,然后hash&(length-1)找到下标,遍历列表找到对应key.但是HashMap是无序、线程不安全的,且HashMap不同步,如果需要线程同步,则可以使用ConcurrentHashMap,也可以使用Collections.synchronizedMap(HashMap map)方法让HashMap具有同步的能力。其实同步同步,就看有没有synchronized关键字。 jdk 1.8 采用的是数组+链表/红黑树,当链表的长度到达阈值时,链表就转换为了红黑树(初始值为8)

b、HashTable

HashTable继承自Dictionary类 ,无序的,HashTable是线程安全的,同步的,即任一时刻只有一个线程能写HashTable, 但是这也让HashTable在读取的时候,速度比HashMap慢,但是写入速度是比HashMap快的


        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        long startHmap = Clock.systemUTC().millis();
        for (int i = 0; i < 100000; i++) {
            map.put(i, i);
        }
        System.out.println("HashMap的插入时间:");
        System.out.println(Clock.systemUTC().millis() - startHmap);

        Map<Integer, Integer> map1 = new Hashtable<Integer, Integer>();
        long startHtable = Clock.systemUTC().millis();
        for (int i = 0; i < 100000; i++) {
            map1.put(i, i);
        }
        System.out.println("HashTable的插入时间:");
        System.out.println(Clock.systemUTC().millis() - startHtable);

HashMap的插入时间:
34
HashTable的插入时间:
19

 Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < 100000; i++) {
            map.put(i, i);
        }
        long startHmap = Clock.systemUTC().millis();
        for (Integer key : map.keySet()) {
            map.get(key);
        }
        System.out.println("HashMap的读取时间:");
        System.out.println(Clock.systemUTC().millis() - startHmap);


        Map<Integer, Integer> map1 = new Hashtable<Integer, Integer>();
        for (int i = 0; i < 100000; i++) {
            map1.put(i, i);
        }
        long startHtable= Clock.systemUTC().millis();

        for (Integer key : map1.keySet()) {
            map1.get(key);
        }
        System.out.println("HashTable的读取时间:");
        System.out.println(Clock.systemUTC().millis() - startHtable);

HashMap的读取时间:
5
HashTable的读取时间:

注意:测试结果非一致,性能有关,hasMap允许多线程操作

c、LinkedHashMap

LinkedHashMap它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表 ,遵从FIFO。

注意:LinkedHashMap在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会 比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

d、TreeMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。红黑树概念,内部通过Comparator比较的方式,进行一个排序,也可以自定义比较器

f、ConcurrentHashMap

ConcurrentHashMap 1.7 支持并发,整个ConcurrentHashMap由一个个Segment组成,也就是很多的槽,默认是16个,这个值可以在初始化的时候进行设置,但是一旦初始化后它是不可以扩容的,但是每一个的Segment[ i ]默认大小是2,扩容因子为0.75,也就是在插入第二个元素时就会进行一次扩容。Segment通过继承ReentrantLock来进行加锁,所以每次操作只是给一个Segment加锁,保证每一个Segment线程安全,来实现全局的线程安全。理论上可以同时支持16个线程并发写,只要是分布在不同的Segment上。

ConcurrentHashMap 1.7与1.8的区别原文出处: 占小狼

 

需要注意的问题:

1.在定义初始数组大小时根据实际情况,一般为2的N次方;

2.根据情况定义数组长度的扩容大小以及数组长度,默认为0.75,避免频繁的扩容导致hash的重计算,一次扩容为2倍 ;

3.Map中,HashMap具有超高的访问速度,如果我们只是在Map 中插入、删除和定位元素,而无关线程安全或者同步问题,HashMap 是最好的选择。

4.如果考虑线程安全或者写入速度的话,可以使用HashTable,当然ConcurrentHashMap是更好的选择

5.如果想按怎么存的顺序怎么取,比如队列形式,排排队。 那么使用LinkedHashMap吧,怎么用怎么爽

6.如果需要让Map按照key进行升序或者降序排序,那就用TreeMap吧

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值