并发工具类和并发容器
为什么要使用ConcurrentHashMap
在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,HashMap在并发执行put操作时会引起死循环,是因为多线程会导致HashMap的Entry链表
形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,就会产生死循环获取Entry。
HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法,其他线程也访问HashTable的同步方法时,会进入阻塞或轮询状态。如线程1使用put进行元素添加,线程2不但不能使用put方法添加元素,也不能使用get方法来获取元素,所以竞争越激烈效率越低。
一些有用的方法
很多时候我们希望在元素不存在时插入元素,我们一般会像下面那样写代码
synchronized(map){
if (map.get(key) == null){
return map.put(key, value);
} else{
return map.get(key);
}
}
putIfAbsent(key,value)方法原子性的实现了同样的功能
V putIfAbsent(K key, V value)
如果key对应的value不存在,则put进去,返回null。否则不put,返回已存在的value。
boolean remove(Object key, Object value)
如果key对应的值是value,则移除K-V,返回true。否则不移除,返回false。
boolean replace(K key, V oldValue, V newValue)
如果key对应的当前值是oldValue,则替换为newValue,返回true。否则不替换,返回false。
public class UseChm {
HashMap<String, String> hashMap = new HashMap<>();
ConcurrentHashMap<String, String> chm = new ConcurrentHashMap<>();
public String putIfAbsent(String key, String value) {
int a;
synchronized (hashMap) {
if (hashMap.get(key) == null) {
return hashMap.put(key, value);
} else {
return hashMap.get(key);
}
}
}
// 存值
public String useChm(String key, String value) {
return chm.putIfAbsent(key, value);
}
}
Hash的解释
散列,任意长度的输入,通过一种算法,变换成固定长度的输出。属于压缩的映射。
Md5,Sha,取余都是散列算法,ConcurrentHashMap中是wang/jenkins算法