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("\n---------------\n"); 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
参考文档
1、Java面试基础
2、