4

say I have the following two classes.

public class Foo {
   private volatile Integer x = 0;
   private volatile boolean istrue = false;

   public void setInt(int x) {
       this.x = x;
   }

   public void setBoolean(boolean istrue) {
       this.istrue = istrue;
   }

   public Integer getInt() {
       return x;
   }
}

vs

public class Bar {
   private volatile AtomicInteger x = 0;
   private volatile AtomicBoolean istrue = false;

   public void setInt(int x) {
       this.x.set(x);
   }

   public void setBoolean(boolean istrue) {
       this.istrue.set(istrue);
   }

   public Integer getInt() {
       return this.x.get();
   }
}

Assume multiple threads can access Foo or Bar. Are both classes thread safe? what is the difference between the two classes really?

Warren Dew
  • 8,790
  • 3
  • 30
  • 44
user1870400
  • 6,028
  • 13
  • 54
  • 115
  • 2
    Given the methods you've written, there is no difference. The difference appears when you try doing more complex operations atomically. – Louis Wasserman Jun 09 '16 at 04:54
  • 1
    The code of the second example will not compile. You cannot assign primitive values such as `0` and `false` to an `AtomicInteger` or `AtomicBoolean`. There's no auto-boxing for these types. – Jesper Jun 09 '16 at 05:11
  • I wonder whether "thread safe" means what you think it means? A class is "thread safe" if there's no way for overlapped calls to its methods from two or more threads to put any of the class's data into some bad state or, to create the appearance of a bad state. What states are allowed for your `Foo` and `Bar` classes? What states would be disallowed? Here's what "thread-safe" does _not_ mean. It does not mean that using this class in your program will make your program thread-safe. – Solomon Slow Jun 09 '16 at 15:41

3 Answers3

1

In the current example you have single assignment statements in the methods. I think you need to come up with a better example. Because the assignment will be executed in a single instruction. Which makes both the implementation thread safe. Even though, it is possible that, two different threads see different values of the int when they access them, because by the time, other thread can potentially reset (set) to a different value.

Check this out: What is thread Safe in java?

Community
  • 1
  • 1
YoungHobbit
  • 13,254
  • 9
  • 50
  • 73
1

Both classes are thread safe as written. The difference between use of a volatile variable and the java.util.concurrent.atomic classes is that the atomic classes permit more complex operations, such as compare and set, to be performed atomically. With just direct access to a volatile variable, there could be a thread context switch between the compare and the set, so you can't rely on the result of the compare still being valid when the set is done.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44
1

Both classes are thread safe. But that is not your issue here.

Foo: reads and writes to the fields are atomic. But more complex operations such as i++ are not. i++ translates to i = i + 1, which decomposes to a read and a write, so there could a thread context switch in between making the entire operation not atomic.

Bar: the volatile makes the access to the Atomic fields themselves atomic, so you can reassign the fields with new references in an atomic ways. The operations on the fields like compareAndSet or inc however are atomic. Question is, do you need atomic write access to the fields or just atomicity on the operations? As the AtomicXXX type are just containers for for values, you typically don't reassign the variable, but reassign values, which is atomic.

So this should be sufficient:

private final AtomicInteger x = new AtomicInteger(0);
private final AtomicBoolean istrue = new AtomicBoolean(false);
Gerald Mücke
  • 10,724
  • 2
  • 50
  • 67