这对我来说可能很天真,但我总是假设下面的代码示例在 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();
// }
}
}