java - 在整数上同步会导致 NullPointerException

标签 java concurrency synchronization

本题基于Synchronizing on an Integer value .

那里的解决方案看起来很棒,只是有一个小问题,它没有解决如何从 ConcurrentHashMap 中删除值的问题。

为了解决我在下面的程序中所做的

import java.util.concurrent.ConcurrentHashMap;

public class Example {

    private final ConcurrentHashMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<Integer, Integer>();

    public void doSomething(int i) {
        synchronized (getLockForId(i)) {
            concurrentHashMap.remove(i);
        }
    }

    public Integer getLockForId(int id) {
        concurrentHashMap.putIfAbsent(id, id); // I want to replace these two
                                                // operation with single one
                                                // since it seems the cause of
                                                // NPE
        return concurrentHashMap.get(id);
    }

    public static void main(String[] args) {
        final Example example = new Example();
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    example.doSomething(++i);
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    example.doSomething(++i);
                }
            }
        }).start();
    }
}

问题是它总是导致 NullPointerException。我的第一个分析是因为我删除了分配给 null 的值,所以它导致了 NullPointerException。所以我在下面做了

    Object obj = new Object();
    synchronized (obj) {
        obj = null;
    }

但以上不会导致 NullPointerException。所以我的问题是为什么在上述情况下会抛出 NullPointerException

即使我这样做

public Integer getLockForId(int id) {
   return concurrentHashMap.putIfAbsent(id, id); 
}

它仍然导致 NullPointerException 因为它只在有其他人返回时返回值 null

最佳答案

是的, 抛出 NullPointerException。考虑这种模式:

 Thread 1                     Thread 2

 putIfAbsent (puts)
 get (returns non-null)
 acquire monitor
                              putIfAbsent (doesn't put)
 remove (removes value)
                              get (returns null)
                              acquire monitor (bang!)

这不是“值被分配给 null”——而是 Map.get 在没有给定键的条目时返回 null。

很难知道推荐什么,因为您的代码确实没有做任何有用的事情。如果您能说出您在真实代码中想要实现的目标,我们就有可能为您提供更好的建议。

编辑:如 Nikita 所述,仅返回 putIfAbsent 的值不起作用,因为它返回 previous 值,或 null 如果它不存在 - 而您想要条目的值。

我怀疑您必须同步对 map 的访问,基本上,使您的 getLockId 方法相对于 remove 操作具有原子性。

关于java - 在整数上同步会导致 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12890214/

相关文章:

java - 如何在 Jira 中以编程方式通过项目 ID 检索项目 key ?

java - 具有内部类和最终变量的线程化 Java 服务器

java - 我应该使用哪个 JSObject?

sockets - Boost Asio,io_service每个内核仅处理一个套接字

java - 多线程 Java 应用程序中的问题 - 同步方法未按预期工作

web-services - 通过 Web 服务调用进行时间同步

找不到死锁

java - AspectJ 的 NoSuchMethodError

java - 在 java 中,我如何处理 CompletableFutures 并获得第一个完成的理想结果?

c# - 为套接字/网络连接同步对象-最佳实践不使用WCF?