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:It’s not that the “value get assigned to null” – it’s that
Map.getreturns 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
putIfAbsentdoesn’t work, as that returns the previous value, ornullif 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
getLockIdmethod atomic with respect to theremoveoperation.