ConcurrentHashMap 产生NullPointerException
今天测试在发给我一段报错日志后,根据日志定位到从ConcurrentHashMap 的缓存中get的时候,ConcurrentHashMap的底层抛出了空指针,当时感觉很奇怪为什么在get的时候产生空指针了呢?
模拟代码:
ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap(); ........................................................ concurrentHashMap.get(传入的参数);
这个地方出现空指针,难道是传入的null 所以出现了空指针了,事实证明确实传入了null,但是我记得hashmap 是可以传入null 的呀? 为什么ConcurrentHashMap 却不行呢?
相应的去验证了一下,remove 方法发现也不能传入null 进去。
一、异常分析
FATAL EXCEPTION: main
java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.remove(ConcurrentHashMap.java:921)
本以为是并发异常,后发现不对,因为ConcurrentHashMap已经使用继承自ReentrantLock的Segment,保证了线程安全,Java如果有这么大的bug肯定早修复了。看了下源码
发现自己大意了,在获取hashCode时NPE(hashMap不会,因为它会对null key做一次处理)。ConcurrentHashMap不接受null key和null value这个常识一时疏忽了,调用的地方确实有可能传入null。这样在remove前进行null判断即可解决。
在问题解决后,想到hashMap和linkedhashMap都允许null key和null value,treeMap不允许null key,但允许null value,而ConcurrentHashMap既不允许null key也不允许null value,why?
二、not allow null key and value
stackoverflow并结合了源码分析了一下
(1) treeMap不允许null key是因为compare会导致NPE, 可通过以下代码实现null key支持
SortedMap<Integer, Integer> map = new TreeMap<Integer, Integer>(new Comparator<Integer>() { @Override
public int compare(Integer arg0, Integer arg1) {
if (arg0 == null) {
if (arg1 == null) return 0;
return -1;
}
if (arg1 == null) return 1;
return arg0.compareTo(arg1);
}
});
(2) ConcurrentHashMap不允许null key和null value,是因为ConcurrentHashMap的锁机制
对于get(Object key)如果返回null,ConcurrentHashMap没办法判断是key不存在还是value就是null。有人得问了那么hashmap呢, 为什么可以,hashmap我们可以通过下面代码实现判断
Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
String key = "aa", value;
synchronized (map) {
if (map.containsKey(key)) {
value = map.get(key);
} else {
throw new Exception("key is not exist");
}
}
使用Collections.synchronizedMap对hashmap加锁,Collections.synchronizedMap的锁是同步锁,就是对象本身,所以synchronized (map)与Collections.synchronizedMap内锁统一。而ConcurrentHashMap的并发控制是利用分离锁实现的(16个重入锁),在外部无法获得锁,自己也没有提供函数进行判断,所以无奈了。
那么有没有办法既保证map的并发安全同时又允许null key和null value呢,当然了,两种方式
第一种实际上面已经展现了,通过Collections.synchronizedMap对hashmap加锁即可。synchronizedMap保证了线程安全,hashmap又允许null key和null value。
不过Collections.synchronizedMap的并发性能自然比不上ConcurrentHashMap的分桶锁机制,如果对性能要求较高
理论上也可以重写ConcurrentHashMap添加一个函数支持上面代码段的并发,但这个要求对ConcurrentHashMap的分离锁相当熟悉
最后:
关于为什么这么设计:
https://laiqitech.com/125/
关于null的一些小知识:
http://www.importnew.com/14229.html
ConcurrentHashMap 产生NullPointerException的更多相关文章
- Java集合---ConcurrentHashMap原理分析
集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...
- ConcurrentHashMap
ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代HashTable.对于ConcurrentHashMap是如何提高其效率的,可能大多人只是知道它使用了多 ...
- ConcurrentHashMap内存泄漏问题
问题背景 上周,同事写了一段ConcurrentHashMap的测试代码,说往map里放了32个元素就内存溢出了,我大致看了一下他的代码及运行的jvm参数,觉得很奇怪,于是就自己捣鼓了一下.首先上一段 ...
- 【JUC】JDK1.8源码分析之ConcurrentHashMap(一)
一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析 ...
- Java集合——ConcurrentHashMap
集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...
- 深入剖析ConcurrentHashMap(2)
转载自并发编程网 – ifeve.com本文链接地址: 深入剖析ConcurrentHashMap(2) 经过之前的铺垫,现在可以进入正题了.我们关注的操作有:get,put,remove 这3个操作 ...
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...
- Java 线程 — ConcurrentHashMap
ConcurrentHashMap ConcurrentHashMap 结构 采用了分段锁的方法提高COncurrentHashMap并发,一个map里面有一个Segment数组--即多个Segmen ...
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
概要 本章是JUC系列的ConcurrentHashMap篇.内容包括:ConcurrentHashMap介绍ConcurrentHashMap原理和数据结构ConcurrentHashMap函数列表 ...
随机推荐
- String 类 常用函数
构造方法摘要: String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String. String(char[] value) ...
- 10th 本周工作量及进度统计
本周PSP C(类别) C(内容) S(开始时间) ST(结束时间) I(中断时间) T(实际时间) 文档 11月22日 规格说明书练习 10:23 15:30 132 175 11月23日 知识点 ...
- how to show video in website
how to show video in website old version browsers https://www.computerhope.com/issues/ch000591.htm h ...
- 通过ClientDataSet复制表的结构及数据
1. 需要2个ClientDataSet组件: 2. clientDataSet1连接目标表,clientDataSet2连接源表,如果无法直接连接,使用DataSetProvider进行桥接: ...
- 理解 Delphi 的类(十一) - 深入类中的方法[8] - 抽象方法与抽象类
//抽象方法类似与接口; 在没有接口的年代 Delphi 是用抽象方法来模拟接口的; 我想它最终会被接口替代. {下面就定义了两个抽象方法} TMyClass = class(TObject) p ...
- python自动化之图像
''' RGBA值:指定颜色中的红.绿.蓝和alpha(透明度)的值 RGBA 名称 (255,255,255,2 ...
- QComboBox 树形视图选择
QComboBox 控件支持树形图显示. A. void QComboBox::setModel(QAbstractItemModel *model): B. void QComboBox::se ...
- BZOJ2876 [Noi2012]骑行川藏 【拉格朗日乘数法】
题目链接 BZOJ 题解 拉格朗日乘数法 拉格朗日乘数法用以求多元函数在约束下的极值 我们设多元函数\(f(x_1,x_2,x_3,\dots,x_n)\) 以及限制\(g(x_1,x_2,x_3,\ ...
- jumpserver 堡垒机搭建
1.摘要 Jumpserver 是一款由python编写开源的跳板机(堡垒机)系统,实现了跳板机应有的功能.基于ssh协议来管理,客户端无需安装agent. 特点: 完全开源,GPL授权 Python ...
- Nginx访问日志分析
nginx默认的日志格式 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$sta ...