Why can't AtomicBoolean be a replacement for Boolean?

家住魔仙堡 提交于 2019-12-06 16:32:49

问题


The Oracle JDK Javadoc for AtomicBoolean states:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicBoolean.html

A boolean value that may be updated atomically. See the java.util.concurrent.atomic package specification for description of the properties of atomic variables. An AtomicBoolean is used in applications such as atomically updated flags, and cannot be used as a replacement for a Boolean.

A colleague and I were trying to figure out a use-case where the AtomicBoolean can't be a substitute and the only thing we can think of is that there are methods the Boolean object has that the AtomicBoolean does not.

Is that the only reason or was there something else in mind when that was written?


回答1:


Boolean is the wrapper class around the primitive boolean. It may be automatically created from a boolean by the compiler (boxing conversion) or converted to a boolean (unboxing conversion). This is not the case for AtomicBoolean where it is a separate class designed for concurrency purposes.

Hence the two classes have different semantics at the language level:

Boolean b = new Boolean(true);
AtomicBoolean ab = new AtomicBoolean(true);
System.out.println(true == b);  // automatic unboxing of Boolean variable
System.out.println(true == ab);  // compiler error



回答2:


Boolean is an immutable value object. It was designed to be unchanging and made final in order to enforce that. java.lang.Boolean has been around since 1.0.

AtomicBoolean is mutable, and designed to get updated so that the updated value is visible across threads. AtomicBoolean was introduced with Java 5.

These are entirely different concepts, which is why AtomicBoolean wasn't designed to extend Boolean. You can't substitute a mutable object for an immutable one without wrecking the expected invariants of the code using it. Code expecting to receive an immutable value could get broken if the atomic version could be passed in in its place.

So here's a use case: if AtomicBoolean was introduced as something that was substitutable for Boolean, you could have a case where a class created before this change could reasonably expect that in some method that returns a Boolean it doesn't need to pass a defensive copy on account of Boolean being immutable. If the reference returned happens to get initialized from a source that changes to use AtomicBoolean instead of Boolean, then that field could now be modified by things calling the method returning Boolean, by casting it to AtomicBoolean.

The atomic classes are designed for working with concurrent updates (as an improvement on volatile), but the most efficient way to design concurrent code is to use immutable values. So be careful not to mistake AtomicBoolean for "the Boolean you use when writing multithreaded code".




回答3:


They're not auto-boxable, so they can't be used in conditionals, e.g.,

// Explodey
if (someAtomicBoolean) {
}



回答4:


Example:

void doSomething( final Boolean flag ) {


  final boolean before = flag.booleanValue();

  do0( flag );

  final boolean after = flag.booleanValue();

  assert before == after;



  if ( flag.booleanValue() ) {
    do1();
  }

  if ( flag.booleanValue() ) {
    do2();
  }

}

can give a different result than

void doSomething( final AtomicBoolean flag ) {


  final boolean before = flag.get();

  do0( flag );

  final boolean after = flag.get();

  assert (before == after) || (before != after);



  if ( flag.get() ) {
    do1();
  }

  if ( flag.get() ) {
    do2();
  }

}

because an AtomicBoolean can change its value while a Boolean cannot.

In the first case, do1() and do2() are either both called or none of them.

In the second case, both, either, or none of them may be called if the AtomicBoolean's value is modified concurrently.

Because Boolean has always been there, and was always defined as immutable, AtomicBoolean, which was introduced much later, cannot be substitutable for Boolean because it behaves differently and code that rightfully relies on the immutability of a Boolean can break if that immutability is destroyed.

Notice that Boolean cannot be substituted for AtomicBoolean and vice versa. They're just not compatible in their semantics.




回答5:


Because Boolean is immutable. See: Why Wrapper class like Boolean in java is immutable? and my answer:


Because 2 is 2. It won't be 3 tomorrow.

Immutable is always preferred as the default, especially in multithreaded situations, and it makes for easier to read and more maintainable code. Case in point: the Java Date API, which is riddled with design flaws. If Date were immutable the API would be very streamlined. I would know Date operations would create new dates and would never have to look for APIs that modify them.

Read Concurrency in Practice to understand the true importance of immutable types.

But also note that if for some reason you want mutable types, use AtomicInteger AtomicBoolean, etc. Why Atomic? Because by introducing mutability you introduced a need for threadsafety. Which you wouldn't have needed if your types stayed immutable, so in using mutable types you also must pay the price of thinking about threadsafety and using types from the concurrent package. Welcome to the wonderful world of concurrent programming.

Also, for Boolean - I challenge you to name a single operation that you might want to perform that cares whether Boolean is mutable. set to true? Use myBool = true. That is a re-assignment, not a mutation. Negate? myBool = !myBool. Same rule. Note that immutability is a feature, not a constraint, so if you can offer it, you should - and in these cases, of course you can.

Note this applies to other types as well. The most subtle thing with integers is count++, but that is just count = count + 1, unless you care about getting the value atomically... in which case use the mutable AtomicInteger.




回答6:


The first main use case of atomic operations (sometimes encapsulated) in any language is compare-and-swap semantics - a fundamental building blocks of the concurrent applications.

The second main use is to hide the complexity of correctly placing memory fences, required for the memory model semantics.

In Java Atomic* encapsulate both of the above, the former - with the platform specific native code, and the latter with the help of volatile keyword.



来源:https://stackoverflow.com/questions/36941526/why-cant-atomicboolean-be-a-replacement-for-boolean

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!