I have a class called LocalIpBlockingDenyListResponse that has two class members viz a List<CustomClass> customClassList and an int storing hashCode() of customClassList
I have atomic reference of above class defined in another class like,
private final AtomicReference<LocalIpBlockingDenyListResponse> denyListAtomicReference;
which is being initialized in the constructor like this
this.denyListAtomicReference = new AtomicReference<>(new LocalIpBlockingDenyListResponse(new ArrayList<>()));
I have this code in a method in same class thats updating atomic reference
try {
List<IpBlockingDenyListRecord> newDenyList = sonarisConsumer. getSonarisSuggestions);
List<IpBlockingDenyListRecord> validatedDenyList = validate (newDenyList); consumptionMetrics.addCount("denyListSize" , validatedDenyList.size), Unit.ONE);
setDenyListAtomicReference(validatedDenyList);
}
This is what setDenyListAtomicReference looks like
void setDenyListAtomicReference(List<IpBlockingDenyListRecords newDenyList) {
denyListAtomicReference.getAndSet(new LocalIpBlockingDenyListResponse(newDenyList));
}
But when I call getIpBlockingDenyList
public List<IpBlockingDenyListRecord> getIpBlockingDenyList() {
log.info("localDenyListSize: " + denyListAtomicReference.get() . getIpBlockingDenyList().size());
return denyListAtomicReference.get().getIpBlockingDenyList();
it returns an empty list.
I tried using set instead of getAndSet. Added bunch of log and debug statements but I am not able to understand why reference is not updating. I have confirmed that validatedDenyList holds the records as expected and is non empty.
Can someone please help me figure out what I am doing wrong?
Multiple
AtomicReference#getcalls is not atomicYou have not included enough detail for us to diagnose this problem. However, I could guess that it may come from one huge mistake you made in your code: Calling
AtomicReference#gettwice.In this block:
… you call
denyListAtomicReference.get()twice. That pair of calls is not atomic. Consider this sequence of events:(your code above)
(some other imaginary code)
denyListAtomicReference.get()returns list xdenyListAtomicReference.set( y )call changes the reference from list x to list ydenyListAtomicReference.get()returns list yIn this scenario you would be reporting on the size of list x while handing off an entirely different list y.
You should change that block to call
getonly once.Don't call
getif you don't want the value returnedSeparate issue: Call
setrather thangetAndSetif you don't capture the returned value.Your line:
… returns the old value contained in the atomic reference before setting a new value in the atomic reference. But you do not bother to capture a reference to the old value returned. So there is no point here in "getting". Just call
setof you don't care about the old value.Alternate example
Let's rewrite your code for simplicity.
Let's use a record for simplicity. Note that we guard our
Listproperty by ensuring it is immutable with call toList.copyOfcombined withnew ArrayList.Assign an object of that record class to an atomic reference. And then replace that reference several times in other threads. I believe this code will result in there never being an empty list.
When run: