Search code examples
javaatomicgetter-setter

What is the proper getter and setter for java atomic properties


I have an atomic boolean property in Java

private AtomicBoolean endOfInputDataSet;

What are the proper getter and setter of this property and what are the consequences of each choice? I can return the AtomicBoolean directly

public AtomicBoolean getEndOfInputDataSet() {
    return this.endOfInputDataSet;
}

public void setEndOfInputDataSet(AtomicBoolean endOfInputDataSet) {
    this.endOfInputDataSet = endOfInputDataSet;
}

or I can return the unwrapped boolean:

public boolean getEndOfInputDataSet() {
    return this.endOfInputDataSet.get();
}

public void setEndOfInputDataSet(boolean endOfInputDataSet) {
    this.endOfInputDataSet.set(endOfInputDataSet);
}

I think the latter solution is just simpler for using by the client and cleaner, but why is it not default when IntelliJ generates the getter and setter?


Solution

  • tl;dr

    👉🏽 Share the Atomic… object container, not its payload value.

    public final AtomicBoolean endOfInputDataSet = new AtomicBoolean( false ) ;
    

    Do share access to AtomicBoolean object

    For multiple threads to coordinate around the value contained in the payload of an Atomic… object, the threads must have simultaneous direct access to the Atomic… object itself.

    Do not share copies of the value within the AtomicBoolean

    Emitting copies of the value to the various threads breaks the atomic nature of the interaction intended by use of Atomic… class. Making copies of the payload’s value is not thread-safe, with the threads now unable to coordinate around a single value.

    Details

    private AtomicBoolean endOfInputDataSet;

    Make that final to prevent another AtomicBoolean object from being assigned to replace the original.

    And you might as well instantiate in the declaration.

    private final AtomicBoolean endOfInputDataSet = new AtomicBoolean( … ) ;
    

    return this.endOfInputDataSet;

    The Atomic… objects are containers that carry a payload while providing thread-safe access to that payload.

    This line returns a reference to that container. The calling programmer may then get or set the content of that payload.

    this.endOfInputDataSet = endOfInputDataSet;

    This line ruins your scenario. You enable the calling programmer to replace your container.

    return this.endOfInputDataSet.get();

    This line returns a copy of the content of your container.

    Be aware that this line‘s method is returning “old news”. There is a beat of time between the end of the get() call and the moment when the calling programmer actually receives the value. During that beat, another thread may have executed a set on the atomic container, changing the content of the container. You have undone the “Atomic” in AtomicBoolean. This code is not thread-safe.

    And there are further beats of time between (a) the calling method receiving our returned copy of the payload’s value and (b) the calling method making use of that value. During these additional beats the calling actual payload in the AtomicBoolean object could be changing.

    this.endOfInputDataSet.set(endOfInputDataSet);

    This line is non-atomic and thread-unsafe in the same way as the line above it.

    why is it not default when IntelliJ generates the getter and setter?

    Because such code is not thread-safe.

    When trying to coordinate multiple threads around a single value, those threads must all be dealing simultaneously with the very same value, the value carried as the payload within the atomic wrapper. To accomplish that, all the threads must be dealing with the atomic wrapper container directly.

    So, you don’t really need getter/setter accessor methods here. Just make the atomic object final and directly accessible (public etc.).

    Think of a bunch of kids in a classroom trying to coordinate their activity around a message in an envelope. If you let various kids copy that message while other kids are changing the message, you have chaos. To coordinate the kids’ activity, they must be simultaneously viewing the one and only message carried in that envelope.