ConcurrentHashMap NullPointerException not allow null key and value

简介:

本文主要由ConcurrentHashMap的一个NullPointerException异常引起,结合ConcurrentHashMap源码分析为什么ConcurrentHashMap不允许空key和value以及如何改造进行支持

1、异常分析
今天碰到一个异常,信息如下:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

FATAL EXCEPTION: main

java.lang.NullPointerException

at java.util.concurrent.ConcurrentHashMap.remove(ConcurrentHashMap.java:921)

at cn.trinea.appsearch.service.AppSearchService.deleteDownloadAndUpdateViewInfo(AppSearchService.java:586)

at cn.trinea.appsearch.service.AppSearchService.installFinish(AppSearchService.java:1111)

at cn.trinea.appsearch.service.AppSearchService.access$10(AppSearchService.java:1102)

at cn.trinea.appsearch.service.AppSearchService$MyHandler.handleMessage(AppSearchService.java:1062)

at android.os.Handler.dispatchMessage(Handler.java:99)

at android.os.Looper.loop(Looper.java:153)

at android.app.ActivityThread.main(ActivityThread.java:5198)

at java.lang.reflect.Method.invokeNative(Native Method)

at java.lang.reflect.Method.invoke(Method.java:511)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:826)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:589)

at dalvik.system.NativeStart.main(Native Method)

本以为是并发异常,后发现不对,因为ConcurrentHashMap已经使用继承自ReentrantLock的Segment,保证了线程安全,Java如果有这么大的bug肯定早修复了。看了下源码

ConcurrentHashMapRemove

发现自己大意了,在获取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?

2、not allow null key and value
stackoverflow并结合了源码分析了一下
(1) treeMap不允许null key是因为compare会导致NPE, 可通过以下代码实现null key支持

Java

1

2

3

4

5

6

7

8

9

10

11

12

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我们可以通过下面代码实现判断

Java

1

2

3

4

5

6

7

8

9

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的分离锁相当熟悉

目录
相关文章
|
安全 Java
【Java面试】ConcurrentHashMap的key为什么不允许为null?
【Java面试】ConcurrentHashMap的key为什么不允许为null?
375 0
|
3月前
|
存储 开发者
HashMap和Hashtable的key和value可以为null吗,ConcurrentHashMap呢
HashMap的key可以为null,value也可以为null;Hashtable的key不允许为null,value也不能为null;ConcurrentHashMap的key不允许为null
|
5月前
|
API 计算机视觉
Using ‘value‘ pointer is unsafe and deprecated. Use NULL as value pointer. To fetch trackbar value s
本文讨论了OpenCV中使用`createTrackbar`时遇到的"Using ‘value’ pointer is unsafe and deprecated"警告,并提供了通过设置空指针或使用回调函数来解决这个问题的方法。
Using ‘value‘ pointer is unsafe and deprecated. Use NULL as value pointer. To fetch trackbar value s
|
5月前
解决微软云Azure Function运行报错-Value cannot be null. (Parameter ‘provider‘)
解决微软云Azure Function运行报错-Value cannot be null. (Parameter ‘provider‘)
94 4
|
5月前
|
C++ Python
【Azure 应用服务】Azure Function Python函数部署到Azure后遇见 Value cannot be null. (Parameter 'receiverConnectionString') 错误
【Azure 应用服务】Azure Function Python函数部署到Azure后遇见 Value cannot be null. (Parameter 'receiverConnectionString') 错误
|
5月前
|
JavaScript 前端开发 C++
【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
|
8月前
|
PHP
Trying to access array offset on value of type null
你就可以避免在null值上尝试访问数组偏移量的错误。 总的来说,当你遇到这个错误时,你应该回顾你的代码,确保在尝试访问数组偏移量之前,相关的变量已经被正确地初始化为一个数组,并且不是null。
1897 4
|
JavaScript API
【Vue】Cannot set reactive property on undefined,null,or primitive value:undefined
【Vue】Cannot set reactive property on undefined,null,or primitive value:undefined
398 0
|
缓存 关系型数据库 MySQL
【异常解决】缓存报错:Null key returned for cache operation (maybe you are using named params on classes withou
【异常解决】缓存报错:Null key returned for cache operation (maybe you are using named params on classes withou
787 0