I believe that the atomicState is only persisted when something on the root object changes. Since this has to happen immediately, and it could be expensive to watch every single child property/object. So for instance in your situation you need to reassign the property on atomicState to the value you changed it to.
atomicState.locks = 
// Event handler execution or something
def locks = atomicState.locks
atomicState.locks = locks
This is how I got it to work in a SmartApp I was working on that needed to aggregate events into 2 second chunks - I would store the events in atomicState until a schedule runs to process them. using atomicState was necessary because sometimes things wouldn’t persist properly because they were being overwritten by another execution running concurrently.
This is why the docs use:
atomicState.counter = atomicState.counter + 1
As it is retrieving the original value, modifying it and reassigning it back to atomicState, but this isn’t obvious and should probably be made clear in the docs.
This is necessary on state because at the end of execution the entire object is persisted regardless, it doesn’t need a trigger like atomicState.