在Integer上同步会导致NullPointerException [英] Synchronizing on an Integer results in NullPointerException

查看:141
本文介绍了在Integer上同步会导致NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题基于在整数值上同步



这个解决方案似乎优秀只有一个小问题,它没有解决的问题,如何从 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); //我想用一个
//替换这两个
//操作,因为它似乎导致
// NPE
return concurrentHashMap.get(id);
}

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

问题是,它总是导致 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 。考虑这种模式:

 线程1线程2 

putIfAbsent(puts)
get返回非空)
获取监视器
putIfAbsent(不放)
删除(删除值)
get(返回null)
获取监视器

这不是值分配给null - 这是 .get 如果给定键没有条目,则返回null。



很难知道要推荐什么,做任何有用的。如果您可以在实际代码中说出您想达到的目标,我们可以给您更好的建议。



编辑:由Nikita注释,只返回 putIfAbsent 的值不起作用,因为它返回上一个值,或 null



我怀疑你会有一个新的同步访问映射,基本上,使 getLockId 方法相对于 remove 操作是原子的。 p>

This question is based on Synchronizing on an Integer value.

The solution there seems excellent only there is small problem it does not address the concern how to delete values from ConcurrentHashMap.

So to address that I did below program

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

Problem is that it always results in NullPointerException. My first analysis was because I am deleting the value it gets assigned to null so it is causing NullPointerException. So I did below

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

But above does not result in NullPointerException. So My question is why it is throwing NullPointerException in above case?

Even if I do

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

It still results in NullPointerException because it only returns value when there is one else return null

解决方案

Well yes, that would throw a NullPointerException. Consider this pattern:

 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!)

It's not that the "value get assigned to null" - it's that Map.get returns null if there's no entry for the given key.

It's hard to know what to recommend, as your code really doesn't do anything useful. If you can say what you're trying to achieve in your real code, we can give you better suggestions, potentially.

EDIT: As noted by Nikita, just returning the value of putIfAbsent doesn't work, as that returns the previous value, or null if it was absent - whereas you want the new value for the entry.

I suspect you'll have to synchronize access to the map, basically, to make your getLockId method atomic with respect to the remove operation.

这篇关于在Integer上同步会导致NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆