这对我来说可能很幼稚,但是我一直认为以下代码示例将始终有效,并且在Java中使用线程安全集合时不会因NullPointerException而崩溃。不幸的是,线程t2似乎能够从两个线程声明下面的containsKey()和get()方法的调用之间的列表中删除该项目。带注释的部分显示了一种无需获取NullPointerException即可处理此问题的方法,因为它只是测试以查看get()的结果是否为null。

我的问题是,使用线程安全集合在Java中处理此问题的正确方法是什么?当然,我可以使用互斥锁或同步块(synchronized block),但是围绕线程安全集合带来的诸多好处和易用性难道不会因此而败北吗?如果我必须使用互斥量或同步块(synchronized block),难道我不能只使用非线程安全收集吗?另外,我一直(在学术界)听说过,检查代码是否为空值是不好的编程习惯。我只是疯了吗?这个问题有简单的答案吗?先感谢您。

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();
//      }
    }
}

最佳答案



仅执行一项操作,因此它是原子的。它也更快。

    Integer value = test.get(0);
    if (value != null) {
         System.out.println(value);
    }



可能吧。我认为最好检查null,如果值可以是null

关于java - 在Java中使用线程安全集合时,处理并发问题的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19120594/

10-12 06:52
查看更多