Java Map容器衍生的常用Map容器分析

HashMap,HashTable,LinkedHashMap,TreeMap,ConcurrentHashMap读取,写入,安全场景测试

HashMap
最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null(多条会覆盖);允许多条记录的值为 Null。非同步的。

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

Hashtable(线程安全容器)
与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。

LinkedHashMap
保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。

1、HashMap,HashTable,LinkedHashMap,TreeMap,ConcurrentHashMap put,get方法耗时比较

  private static Integer forTimes = 10000000;
  private static Integer readTimes = 10000000;
    public static void hashmap(){
    
    	//map写入
        long dateOne = System.currentTimeMillis();
        //HashMap设置初始大小,当初始数组满足使用时,则HashMap不需要再进行扩容,减少或避免rehash次数  注:初始大小为非必须参数
        HashMap<Object,Object> hashMap = new HashMap<>(10000000);
        for (int i = 0; i < forTimes ; i++) {
            hashMap.put(i,i);
        }
        long dateTwo = System.currentTimeMillis();
        System.out.println("HashMap,指定初始化容器大小put使用时间:"+(dateTwo-dateOne));

		//循环顺序读取
        long dateThree = System.currentTimeMillis();
        for (int i = 0; i <forTimes ; i++) {
            hashMap.get(i);
        }
        long dateFour = System.currentTimeMillis();
        System.out.println("HashMap,指定初始化容器大小get使用时间:"+(dateFour-dateThree));

		//随机数读取
        long datefive = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < readTimes ; i++) {
            hashMap.get(random.nextInt(readTimes));
        }
        long datesix = System.currentTimeMillis();
        System.out.println("HashMap,指定初始化容器大小,随机取值使用时间:"+(datesix-datefive));

        hashMap.clear();
    }
    
每个map类型测试多次次均值    

HashMap,未指定初始化容器大小put使用时间:11298 | 9652 | 9846
HashMap,未指定初始化容器大小get使用时间:1170 | 779 | 929
HashMap,未定初始化容器大小,随机取值使用时间:2641 | 2555 | 2587
Process finished with exit code 0

HashMap,指定初始化容器大小put使用时间:11241 | 10686 | 9676
HashMap,指定初始化容器大小get使用时间:1234 | 818 | 848
HashMap,指定初始化容器大小,随机取值使用时间:2713 | 2579 | 2629
Process finished with exit code 0  

linkedHashMap,put使用时间:9173 | 9411 | 8446 | 10143
linkedHashMap,get使用时间:1066 | 574 | 640 | 8332
linkedHashMap,随机取值使用时间:1786 | 2148 | 2016 | 2221
Process finished with exit code 0


hashtable,put使用时间:8643  |  8204 | 12032
hashtable,get使用时间:1219 | 1132 | 1459
hashtable,随机取值使用时间:2350 | 2452 | 2387
Process finished with exit code 0

treeMap,put使用时间:15060  | 15434  |  14007
treeMap,get使用时间:1562  | 1946  |  1700
treeMap,随机取值使用时间:11087  |  11280  |  11096
Process finished with exit code 0

concurrentHashMap,put使用时间:12110  |  10941  | 11672
concurrentHashMap,get使用时间:941  |  1556 | 1584
concurrentHashMap,随机取值使用时间:2552  |  2418 | 2441
Process finished with exit code 0
  • 前景:以上测试,均在main方法中,单次单个方法,执行多次得到的结果。linkedHashMap测试结果有疑义,原因还未找到——读取跳值幅度过大
  • 由以上测试结果可见:
  •  a.HashMap初始值的设定,对put,get耗时影响难以察觉,默认数组初始值为16,一千万次插入,扩容开销这里并未在时间上体现
    
  •  b.单次执行,不接入业务逻辑,HashMap,linkedHashMap,HashTable,concurrentHashMap读写差别都不是很大(毫秒级)。
    
  •  c.TreeMap写入,读取耗时明显耗时最多,随机取值时更加明显。TreeMap写入时根据Key排序(后面会贴上测试代码)
    

2、HashMap,HashTable,LinkedHashMap,TreeMap,ConcurrentHashMap 储存排序测试

    public static void testSort(){
        Random random = new Random();

        HashMap<Object,Object> hashMap = new HashMap<>(20);
        LinkedHashMap<Object,Object> linkedHashMap = new LinkedHashMap<>();
        Hashtable<Object, Object> hashtable = new Hashtable<>();
        TreeMap<Object,Object> treeMap = new TreeMap<>();
        ConcurrentHashMap<Object,Object> concurrentHashMap = new ConcurrentHashMap<>();

        for (int i = 0; i < 20 ; i++) {
            int c = random.nextInt(100);
            hashMap.put(c,i);
            linkedHashMap.put(c,i);
            hashtable.put(c,i);
            treeMap.put(c,i);
            concurrentHashMap.put(c,i);
        }

        System.out.println("hashMap"+hashMap);
        System.out.println("linkedHashMap"+linkedHashMap);
        System.out.println("hashtable"+hashtable);
        System.out.println("treeMap"+treeMap);
        System.out.println("concurrentHashMap"+concurrentHashMap);

    }

hashMap{1=17, 66=19, 36=3, 70=1, 10=6, 43=18, 45=4, 79=16, 16=9, 81=12, 50=5, 18=15, 52=8, 57=2, 27=7, 59=11, 92=13, 95=0}
linkedHashMap{95=0, 70=1, 57=2, 36=3, 45=4, 50=5, 10=6, 27=7, 52=8, 16=9, 92=13, 59=11, 81=12, 18=15, 79=16, 1=17, 43=18, 66=19}
hashtable{92=13, 45=4, 43=18, 36=3, 81=12, 79=16, 27=7, 70=1, 66=19, 18=15, 16=9, 59=11, 10=6, 57=2, 52=8, 50=5, 1=17, 95=0}
treeMap{1=17, 10=6, 16=9, 18=15, 27=7, 36=3, 43=18, 45=4, 50=5, 52=8, 57=2, 59=11, 66=19, 70=1, 79=16, 81=12, 92=13, 95=0}
concurrentHashMap{1=17, 66=19, 36=3, 70=1, 10=6, 43=18, 45=4, 79=16, 16=9, 81=12, 50=5, 18=15, 52=8, 57=2, 27=7, 59=11, 92=13, 95=0}

Process finished with exit code 0
  • 由上面测试案例可以看出
  • TreeMap存储值是按key值进行了排序,LinkedHashMap按插入顺序进行了排序,其他的Map衍生容器都是无序的
    

3、HashMap,HashTable,LinkedHashMap,TreeMap,ConcurrentHashMap 线程安全容器

  • HashTable,ConcurrentHashMap都是线程安全集合,在多线程中执行时,HashTable,ConcurrentHashMap的耗时对比,测试一将不再适用
    
  • HashMap,LinkedHashMap,TreeMap非线程安全容器,但也可以使用synchronized线程锁关键字,进行安全控制
    
  • 线程安全这里不帖代码了,并发高时,非线程安全容器读取,写入时易发生混淆。简单说A线程写入数据,还未读取,B线程争取开销后,立即写入,A进行读取时,读取的则是被B线程覆盖后的数据。

测试一中,是单次执行单个方法测试Map衍生容器耗时。若是五个方法同时执行,执行一次改变方法执行顺序,执行的结果截然不同,耗时差异很大,这是为什么,有没有大佬解答一下。(个人猜想是涉及到类加载编译的问题?)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值