zoukankan      html  css  js  c++  java
  • Java之HashMap、Hashtable对比测试

    Java 8

    ---

    编写程序测试 HashMap、Hashtable 的一些功能,并对二者进行对比。来自博客园

    截取 参考文档1 的相关内容:

    JDK源码:初始容量、loadFactor是两个重要概念,影响到 扩容时的性能。来自博客园

    public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
        // 构造函数 4个
        public HashMap() {...}
        public HashMap(int initialCapacity) {...} // 最高频
        public HashMap(int initialCapacity, float loadFactor) {...}
        public HashMap(Map<? extends K, ? extends V> m) {...}
    }
    
    public class Hashtable<K,V>
        extends Dictionary<K,V>
        implements Map<K,V>, Cloneable, java.io.Serializable {
        // 构造函数 4个
        public Hashtable() {...}
        public Hashtable(int initialCapacity) {...} // 最高频
        public Hashtable(int initialCapacity, float loadFactor) {...}
        public Hashtable(Map<? extends K, ? extends V> t) {...}
    }
    

    测试程序:来自博客园

    package aug;
    
    import java.time.Duration;
    import java.time.Instant;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Hashtable;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.function.Consumer;
    
    public class Test80201 {
    
    	// 输出信息使用
    	private static Consumer<Object> cs = System.out::println;
    	
    	public static void main(String[] args) {
    		test1();
    		
    		cs.accept("
    ---------------
    ");
    		
    		test2();
    	}
    	
    	public static void test1() {
    		// 1、插入null值
    		cs.accept("1、插入null值");
    		Map<String, Integer> map = new HashMap<>(8);
    		map.put("a", 1);
    		map.put("b", 2);
    		map.put("c", null);
    		map.put(null, null);
    		cs.accept("map=" + map);
    		cs.accept("ma.null=" + map.get(null));
    		map.put(null, 999);
    		cs.accept("map=" + map);
    		cs.accept("map.null=" + map.get(null));
    		cs.accept("");
    		
    		Hashtable<String, Integer> table = new Hashtable<String, Integer>(8);
    		table.put("a", 111);
    		table.put("b", 222);
    		// 不能插入null
    //		table.put("c", null);
    		// 不能插入null
    //		table.put(null, 333);
    		cs.accept("table=" + table);
    		cs.accept("");
    		
    		// 2、迭代器
    		cs.accept("2、迭代器");
    		Iterator<Entry<String, Integer>> iter = map.entrySet().iterator();
    		cs.accept("输出iter:");
    		while(iter.hasNext()) {
    			Entry<String, Integer> ent = iter.next();
    			cs.accept(ent);
    			
    			// fail-fast
    			// java.util.ConcurrentModificationException
    //			map.remove(ent.getKey());
    		}
    		
    		Set<Entry<String, Integer>> tset = table.entrySet();
    		Iterator<Entry<String, Integer>> iter2 = tset.iterator();
    		cs.accept("输出iter2:");
    		while(iter2.hasNext()) {
    			Entry<String, Integer> ent = iter2.next();
    			cs.accept(ent);
    			
    			// fail-fast
    			// java.util.ConcurrentModificationException
    //			table.remove(ent.getKey());
    		}
    		
    		cs.accept("");
    		
    		cs.accept("map=" + map);
    		cs.accept("table=" + table);
    		
    		cs.accept("");
    		cs.accept("talbe.keys:");
    		Enumeration<String> keys = table.keys();
    		while(keys.hasMoreElements()) {
    			String key = keys.nextElement();
    			cs.accept(key + "=" + table.get(key));
    			
    			// 未发生异常,删除成功
    			// 若发生在其它线程呢?
    			table.remove(key);
    		}
    		
    		cs.accept("");
    		
    		cs.accept("map=" + map);
    		cs.accept("table=" + table);
    	}
    	
    	/**
    	 * 多线程测试
    	 * @author ben
    	 * @date 2021-08-02 10:31:25 CST
    	 */
    	public static void test2() {
    		ExecutorService es1 = Executors.newFixedThreadPool(4);
    		
    		// 关注点:
    		// 写入数据的最终数量是否符合预期;写入数据的效率;
    		
    		final int size = 4096;
    		
    		cs.accept("3、两个线线程往HashMap中写数据");
    		final Map<String, Integer> map = new HashMap<>(size);
    		es1.submit(()->{
    			int end = size/2;
    			Instant inst1 = Instant.now();
    			for (int i=0; i<end; i++) {
    				map.put("a"+i, i);
    			}
    			Instant inst2 = Instant.now();
    			cs.accept("HashMap插入" + end + "个元素,耗时:" + Duration.between(inst1, inst2).toNanos() + "纳秒");
    		});
    		es1.submit(()->{
    			int end = size/2;
    			for (int i=0; i<end; i++) {
    				map.put("b"+i, i);
    			}
    		});
    		
    		try {
    			// 睡眠5秒
    			Thread.sleep(5000);
    		} catch (InterruptedException e) {
    			// nothing
    		}
    		
    		// 每次执行可能不同,测试的插入数量越多,误差越大
    		cs.accept("map.size=" + map.size());
    		
    		cs.accept("4、两个线线程往Hashtable中写数据");
    		final Hashtable<String, Integer> table = new Hashtable<>(size);
    		es1.submit(()->{
    			int end = size/2;
    			Instant inst1 = Instant.now();
    			for (int i=0; i<end; i++) {
    				table.put("c"+i, i);
    			}
    			Instant inst2 = Instant.now();
    			cs.accept("Hashtable插入" + end + "个元素,耗时:" + Duration.between(inst1, inst2).toNanos() + "纳秒");
    		});
    		es1.submit(()->{
    			int end = size/2;
    			for (int i=0; i<end; i++) {
    				table.put("d"+i, i);
    			}
    		});
    		
    		try {
    			// 睡眠5秒
    			Thread.sleep(5000);
    		} catch (InterruptedException e) {
    			// nothing
    		}
    		
    		cs.accept("table.size=" + table.size());
    		
    		es1.shutdown();
    	}
    
    }
    

    执行结果:

    1、插入null值
    map={null=null, a=1, b=2, c=null}
    ma.null=null
    map={null=999, a=1, b=2, c=null}
    map.null=999
    
    table={b=222, a=111}
    
    2、迭代器
    输出iter:
    null=999
    a=1
    b=2
    c=null
    输出iter2:
    b=222
    a=111
    
    map={null=999, a=1, b=2, c=null}
    table={b=222, a=111}
    
    talbe.keys:
    b=222
    a=111
    
    map={null=999, a=1, b=2, c=null}
    table={}
    
    ---------------
    
    3、两个线线程往HashMap中写数据
    HashMap插入2048个元素,耗时:2990900纳秒
    map.size=3935
    4、两个线线程往Hashtable中写数据
    Hashtable插入2048个元素,耗时:13965500纳秒
    table.size=4096
    

    同步Map 1:更改map为 Collections.synchronizedMap(new HashMap<>(size)); 

    只执行 test2() 的测试结果:

    
    ---------------
    
    3、两个线线程往HashMap中写数据
    HashMap插入2048个元素,耗时:4987100纳秒
    map.size=4096
    4、两个线线程往Hashtable中写数据
    Hashtable插入2048个元素,耗时:10967600纳秒
    table.size=4096
    

    结果分析:

    map也写入了符合预期的数据,性能 比 Hashtable 好很多。

    同步Map 2:更改map为 new ConcurrentHashMap<String, Integer>(size);

    只执行 test2() 的测试结果:

    
    ---------------
    
    3、两个线线程往HashMap中写数据
    HashMap插入2048个元素,耗时:1996600纳秒
    map.size=4096
    4、两个线线程往Hashtable中写数据
    Hashtable插入2048个元素,耗时:8028700纳秒
    table.size=4096
    

    结果分析:

    map也写入了符合预期的数据,性能 比 Hashtable 好很多。

    参考文档

    1、Java面试基础

    2、

  • 相关阅读:
    HttpServletRequest和ServletRequest的区别.RP
    HttpServletResponse和HttpServletRequest详解.RP
    图(最短路径算法————迪杰斯特拉算法和弗洛伊德算法).RP
    简单VBS教程.RP
    关于堆排序、归并排序、快速排序的比较
    函数的返回值是如何带出和接收的以及内存中的活动情况.RP
    SDUT 3402 数据结构实验之排序五:归并求逆序数
    常用工具
    图--生成树和最小生成树.RP
    python 带BOM头utf-8的响应解码
  • 原文地址:https://www.cnblogs.com/luo630/p/15089158.html
Copyright © 2011-2022 走看看