我们都知道hashmap是线程不安全的,而效率也比较高,他允许我们存入null键及null值;
而 hashtable 是线程安全的,其效率比较低,不允许我们存入null键和null值;
除了非同步及允许使用null值,hashmap与hashtable基本相同;
那么为什么hashtable是线程安全的呢?我们可以翻看一下:
例如:put 方法,hashtable中几乎所有的方法都是被synchronized 修饰的;以保证其安全性;
synchronized 可以修饰静态方法(锁对象为本类的字节码文件对象)、修饰普通方法(锁对象为this,即谁调用了它)、修饰某段代码(锁对象为任意对象);
再来说hashmap,它的get put 方法没有加同步,那么意味着,如果2个线程同时put了两个相同的key时,这2个key会被放到数组中的同一位置,(hashmap 中的key是
用数组来存储的),就会导致其中一个线程put的数据被覆盖;另外:hashmap并发执行put 操作时会引起死循环(其实是发生在数组扩容时,hashmap 中的node链表
形成环形数据结构)。
所以在api中给出了这样的方法保证hashmap的安全:
Map m = Collections.synchronizedMap(new HashMap(...));
当然还有另外一种方法就是:使用ConcurrentHashmap:这个类遵守与Hashtable
相同的功能规范,即支持Hashtable
的所有功能(注意:它不 允许将 null 用作键或值);
除此之外还支持多线程对map 的读操作,在执行写操作时,CHM只锁住部分的Map,同时支持16个进程进行写操作,读操作不受限制;
原因在于
ConcurrentHashmap引用了锁分割,将map分割为16部分(默认初始容量为16),由不同的锁控制;
不过,尽管所有操作都是线程安全的,获取操作不 必锁定,不支持某种以所有访问的方式锁定整个表,CHM不会锁住整个Map
ConcurrentHashmap 要比
Map m = Collections.synchronizedMap(new HashMap(...)); 方法 和hashtable 效率相对较高(应用场景:读取多于写入);