HashMap不是线程安全,可能在并发情况下发生以下问题:
1、数据丢失,如果多个线程同时put相同的key时,那么其中一个线程的数据将会丢失或get不到了。
2、Map.size()与实际不合,多线程环境下put的HashMap会被“损坏”,其中会造成size与实际不符合。
3、导致死循环,当HashMap在做动态扩容是,需要对整个Hash表里的无素都需要被重算一遍。这叫rehash,并发环境下的rehash过程可能会带来循环链表,导致死循环致使线程挂掉。
为了解决以上的问题JDK提供了2个线程安全的HashMap:HashTable和ConcurrentHashMap:
1、HashTable 底层使用了synchronized,对所有的方法增加了锁,就解决了并发问题,但同时降低了效率。
2、为了解决效率问题,JDK又提供了一个既能保持线程安全,有可以解决效率问题的工具类ConcurrentHashMap。
ConcurrentHashMap原理:分段锁
1、HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
2、简单的说就是把数组问题多个段,每个段各有一把锁。JDK1.8后则改为每个数组的元素一个锁
实例代码:package com.what21;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapMain {
/**
* @param args
*/
public static void main(String[] args) {
Map map = new ConcurrentHashMap();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
// map.keySet().iterator();
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println(key + ","+ map.get(key));
if (key.equals("3")) {
map.put(key + "key", "3");
}
}
}
}