非线程安全。(非同步)
怎么才能让 HashMap 变成线程安全的呢?
我认为主要可以通过以下三种方法来实现:
Hashtable通过对整个表上锁实现线程安全,因此效率比较低
[[Java HashTable]]
(不是绝对的线程安全)
[[Java synchronizedMap]]
它使用分段锁来保证线程安全
通过前两种方式获得的线程安全的HashMap在读写数据的时候会对整个容器上锁,而ConcurrentHashMap并不需要对整个容器上锁,它只需要锁住要修改的部分就行了
[[Java ConcurrentHashMap]]
HashTable 中所有 CRUD 操作
都是线程同步的,同样的,线程同步的代价就是效率变低了。
所有的读写操作都进行了锁保护,是线程安全的。
private transient Entry<?,?>[] table; //底层保存节点的数组
private transient int count; //记录表中的节点数
private int threshold; //阈值,当表的节点数>=该阈值,会进行扩容
private float loadFactor; //负载因子,计算阈值用的
private transient int modCount = 0; //Hashtable在结构上被修改的次数
// 计算节点在数组的下标
int index = (hash & 0x7FFFFFFF) % tab.length;
public synchronized boolean containsKey(Object key) {
Entry<?,?> tab[] = table; //表
int hash = key.hashCode();
//计算key在数组中的下标
int index = (hash & 0x7FFFFFFF) % tab.length;
//遍历链表
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return true;
}
}
return false;
}
方法如下:
// 返回由指定映射支持的同步(线程安全的)映射
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
private static Map<String,List<MaxMinTimeValue>> maxMinTimeValueMap = Collections.synchronizedMap(new LinkedHashMap<String,List<MaxMinTimeValue>>());
private static Map<String,MaxMinTimeValue> maxMinTimeValueMap4Kuashiduan = Collections.synchronizedMap(new LinkedHashMap<String,MaxMinTimeValue>());
它是将map的每个方法都加了同步(都加了虚拟锁机制)
但是他们放在一起操作(多个该map(map是通过Collections.synchronizedMap来定义的)的方法)还是会出现线程不安全的事情。如当程序正在执行containsKey方法时,另一个程序已经将key删除了。会出现这种情况。就是会有两个线程同时操作map,导致不可预见性的结果。这时为了解决此问题,还是要加上同步机制。如:
private static final Object object=new Object();
public void removeKey(String key){
synchronized(object){
if(map.containsKey(key)){//containsKey方法是线程安全的方法
map.remove(key);//remove方法也是线程安全的方法。
}
}
}
故 Collections.synchronizedMap 也只是有条件的线程安全的。而不是绝对的线程安全的。还是少用的好。
再 Java 1.5 版本引入 ConcurrentHashMap,实现线程安全。
ConcurrentHashMap 将 hash 表分为 16 个桶(默认值),诸如 get,put,remove 等常
用操作只锁当前需要用到的桶。试想,原来只能一个线程进入,现在却能同时 16 个写线程进入(写线程
才需要锁定,而读线程几乎不受限制,并发性的提升是显而易见。
ConcurrentHashMap是一个哈希表,支持检索的全并发和更新的高预期并发。此类遵循与 Hashtable 相同的功能规范,并包含 Hashtable 的所有方法。ConcurrentHashMap 位于 java.util.Concurrent 包中。
当一个线程迭代 Map 对象时,其他线程被允许修改 Map,我们不会得到 ConcurrentModificationException
键和值都不允许为 Null。
略……
JDK 1.7 版本
JDK 1.8 版本