这对我来说可能是天真的,但我总是假设下面的代码示例总是有效,并且在Java中使用线程安全集合时不会因NullPointerException而崩溃。不幸的是,线程t2似乎能够在两个线程声明下面的containsKey()和get()方法之间的列表中删除项目。注释部分显示了一种处理此问题的方法,但没有得到NullPointerException,因为它只是测试以查看get()的结果是否为null。
我的问题是,使用线程安全集合在Java中处理这个问题的正确方法是什么?当然,我可以使用互斥锁或同步块,但这不会破坏线程安全集合周围的许多好处和易用性吗?如果我必须使用互斥锁或同步块,我不能只使用非线程安全集合吗?另外,我一直听说(在学术界)检查空值的代码是糟糕的编程习惯。我只是疯了吗?这个问题有一个简单的答案吗?提前谢谢。
package test;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Test {
public static void main(String[] args) {
final Map<Integer, Integer> test = new ConcurrentHashMap<>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
test.put(0, 0);
Thread.yield();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
test.remove(0);
Thread.yield();
}
}
});
t1.start();
t2.start();
while(true) {
if (test.containsKey(0)) {
Integer value = test.get(0);
System.out.println(value);
}
Thread.yield();
}
// OR
// while(true) {
// Integer value = test.get(0);
// if (value != null) {
// System.out.println(value);
// }
// Thread.yield();
// }
}
}
答案 0 :(得分:3)
使用线程安全集合在Java中处理此问题的正确方法是什么?
只执行一次操作,因此它是原子的。它也更快。
Integer value = test.get(0);
if (value != null) {
System.out.println(value);
}
我一直听说(在学术界)检查空值的代码是糟糕的编程习惯。我只是疯了吗?
可能。我认为检查null
,如果值为null
是最佳做法。
答案 1 :(得分:2)
这个
if (test.containsKey(0)) {
Integer value = test.get(0);
System.out.println(value);
}
仍然不是原子的。检查containsKey
后,可以添加/删除一个帖子。
您需要在该代码段周围的共享资源上进行同步。或者null
之后检查get
。
ConcurrentHashMap
中的所有操作都是线程安全的,但它们不会超出方法边界。
答案 2 :(得分:2)
你滥用线程安全的集合。
线程安全集合无法阻止其他代码在containsKey()
和get()
之间运行。
相反,它们为您提供了额外的线程安全方法,这些方法将自动检查并获取元素,而不允许其他线程干扰。
这意味着您永远不应该通过基本集合接口(Map
或List
)使用并发集合。
相反,请将您的字段声明为ConcurrentMap
。
在您的情况下,您可以简单地调用get()
,如果找不到该键,它将以原子方式返回null。
除此之外别无选择null
。 (与使用Maybe monad的更优雅的函数语言不同)
答案 3 :(得分:2)
此外,我一直听说(在学术界)检查空值的代码是不好的编程习惯。
使用通用地图,当您编写Integer i = map.get(0);
时,如果i
是null
,则无法断定0
不在地图中 - 它可能是但是映射到null
值。
但是,使用ConcurrentHashMap,您可以保证没有空值:
与Hashtable类似,但与HashMap不同,此类不允许将null用作键或值。
所以使用:
Integer i = map.get(0);
if (i != null) ...
非常好。