Why can't AtomicBoolean be a replacement for B

2019-04-17 19:21发布

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?

7条回答
男人必须洒脱
2楼-- · 2019-04-17 19:51

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
查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-04-17 19:53

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.

查看更多
不美不萌又怎样
4楼-- · 2019-04-17 19:55

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".

查看更多
倾城 Initia
5楼-- · 2019-04-17 20:01

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.

查看更多
迷人小祖宗
6楼-- · 2019-04-17 20:12

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

// Explodey
if (someAtomicBoolean) {
}
查看更多
一纸荒年 Trace。
7楼-- · 2019-04-17 20:16

One use case is that AtomicBoolean does not extend Boolean. Thus, if you have a method such as:

void foo (Boolean b) {
    doStuff();
}

Then you may not pass an AtomicBoolean as a parameter to foo. (You would have to call the get() method of the AtomicBoolean.)

查看更多
登录 后发表回答