Can we have an AtomicEnum in Java?
Asked Answered
L

4

9

Today I saw this utility class for AtomicEnum but I wonder if it is possible to have an atomic enum why it is not included in Java standard libraries? In fact I have so much doubt if it can be really atomic and if this utility class works.

The AtomicEnum class is this

  1. How can I examine if it does the operations atomically?
  2. Is there a tool for seeing the compiled code and be sure that it does really all in only one machine instruction?
  3. Is it possible to discover it from the code?
  4. So if this Atomic enum works, I can have an attribute AtomicEnum and it will be possible to use it safely without volatile keyword and synchronized getters and setters?
Lockup answered 19/12, 2013 at 15:51 Comment(2)
Please try to find a mirror for the file, because the link is dead.Poltroonery
Not sure if this is the original file but I found this: github.com/stratosphere/stratosphere/blob/master/…Clothesbasket
S
24

Today I saw this utility class for AtomicEnum but I wonder if it is possible to have an atomic enum why it is not included in Java standard libraries?

The AtomicEnum class that you linked to is just wrapping the AtomicReference class which gives concurrent access for any Object.

Really a volatile enumField is all you need if you have multiple threads that are getting and setting it concurrently. The volatile keyword ensures that updates made by one thread are seen by other threads.

You need the AtomicReference if you need to do a compareAndSet(...) type of method – atomically test if the field is a particular value and only then update it. You could use AtomicReference something like the following:

private final AtomicReference<MyEnum> atomicColor = new AtomicReference<>();
...
atomicColor.set(ColorEnum.RED);
...
if (atomicColor.compareAndSet(ColorEnum.RED, ColorEnum.GREEN)) {
   ...
}
...
ColorEnum color = atomicColor.get();

How can I examine if it does the operations atomically?

AtomicReference is part of the java.util.concurrent classes which are well tested.

Is there a tool for seeing the compiled code and be sure that it does really all in only one machine instruction?

That shouldn't be necessary. You can take a look at the AtomicReference source if you care to see what it is doing. Unfortunately the real magic is in the sun.misc.Unsafe native code.

Is it possible to discover it from the code?

That shouldn't be necessary.

So if this Atomic enum works, I can have an attribute AtomicEnum and it will be possible to use it safely without volatile keyword and synchronized getters and setters?

Yes, AtomicReference wraps a volatile V value so you don't have to do it.

Snip answered 19/12, 2013 at 15:52 Comment(10)
Thanks. So if I wrap any object with atomic reference it will be completely thread-safe, including all its attributes? Or is it possible only for an immutable object like enum? so I will be able to be sure that if I substitute an enum with an atomic enum no object will lock my class in this example? stackoverflow.com/questions/20685372Lockup
No. It only protects the reference. If you want to have a mutable object then you need to synchronize more heavily.Poliard
Enum's are by default thread-safe. The AtomicReference makes your field atomic so multiple threads can test and change it to a different enum atomically @Johnny.Snip
@Gray: good mention: "by default": by adding mutable fields to your enum you can "break" its thread-safety quite easily! Don't do that.Intrigue
So if I have a very simple c-like enum I don't need even to use a synchronized getters and setters or anything such as AtomicReference?Lockup
The reason why we use volatile is because of memory synchronization. If one thread changes a shared enum, other threads won't necessarily see the update. The reason why we use AtomicReference is so we can compareAndSet(...) atomically. If you don't need the atomic method (i.e. you just set or get it) then a volatile enumField is enough. But if you have multiple threads you need the volatile @Johnny.Snip
So if only one thread writes and the others read I will not need synchronization? Or if all only read or all only write? @SnipLockup
volatile provides memory synchronization. What is doesn't do is block the threads. You don't need to get a synchronized lock to update or read an enum field, no @Johnny. Even if all threads are reading and writing you don't need it. Time to read some docs: docs.oracle.com/javase/tutorial/essential/concurrency/sync.htmlSnip
Sorry @Gray! I was under the effect of Java effective that says: "synchronization has no effect unless both read and write operations are synchronized." It's example is with "int" and tells that "private static volatile int nextSerialNumber = 0;" needs synchronization for ++ operation! I thought that such a situation applies to Enum too! As it's not a primitive. Thanks a lot for your answer and the comments.Lockup
The reason why ++ is special is that it is 3 operations: get, increment, set. That has to be done atomically. There is no such operation when setting an enum. Also, you can use AtomicInteger which can atomically increment without a synchronized lock @Johnny.Snip
I
3

This AtomicEnum is simply a thin wrapper around an AtomicReference, which makes sense since a n enum value is simply an object (reference).

So if AtomicReference works correctly (and I think we can assume that), the AtomicEnum will work as well.

Intrigue answered 19/12, 2013 at 15:53 Comment(2)
Since Enums have a unique integer identifier ("ordinal"), wouldn't it be a bit better to use AtomicInteger?Stock
@androiddeveloper: you could, but I don't really see the advantage. Storing the ordinal is less save (you could store something that's out of the range), requires more work to store/restore (mapping to/from the actual enum) and is the same storage space on most platforms (definitely on 32bit platforms and usually even on 64bit platforms).Intrigue
C
1

The access to the reference is atomic, but the access to the object is not. So a change in value of reference will be properly propagated across all threads but a change in the actual enum object might not.
Example...

enum Weekdays {
    public int rank = 0;
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY;
}

Case 1:

AtomicEnum<Weekdays> today = Weekdays.TUESDAY;

Each thread sharing 'today' will have a reference of Weekdays.TUESDAY

Case 2:

today.rank = 3;

There is no guarantee that each thread will have the updated rank. (rank is not volatile. Everyone maintains separate copy of the object in cache.)

So reference access is atomic but that to object is not.
Note:
1) Atomic access does not mean execution in one machine instruction. But logically it can be thought like this. Although it is indivisible, it can comprise of several instructions.
2) Even if such tool existed, it would be too difficult to test it since the update process is almost unpredictable. So false positive results are possible.

Hope this helps.

Confection answered 19/12, 2013 at 16:46 Comment(5)
You have pointed a good point I didn't know "Atomic access does not mean execution in one machine instruction." thanks!Lockup
If you have an AtomicEnum (or really any AtomicReference) the only way to access the actual object is through a volatile field or some heavier synchronization so case 2 isn't a problem either. I.e. "a change in the actual enum object might not" is wrong. But this is mixing up differences between atomic operations (a write to an int is atomic by definition though) and visibility guarantees. You can have atomic operations that don't give you any visibility guarantees although it's rare.Dizon
You are correct, but if you haven't used a volatile field or some heavier synchronization (as in the given case), "a change in the actual enum object might not be visible". I just tried to keep use case simple and avoid rare cases for simplicity.Confection
It's confusing if you're talking about just using the enum directly or if you're referring to the AtomicReference<SomeEnum> version. In the first case you are correct, but in the second case you're guaranteed to get the necessary visibility guarantees. To me it reads like you're talking about AtomicReference (or well AtomicEnum) in the second case too, you may just want to rephrase it.Dizon
It is AtomicEnum in both cases. So first case is fine right? In second case, no change is being made to the reference itself. the object it is referring to is being changed. So there is no visibility guarantee. If two copies of the object are in L1 cache of two cores, we can't be sure that they'll be updated globally.Confection
A
1

I think there is no point writing any such class. In fact if you are writing such class you need to rethink about the responsibility of the class. ENUMs are absolutely thread safe so I am not sure why someone need AtominEnum, or is it just some class which is Atomic and also using some enum but then naming it AtomicEnum is very confusing not good in design or naming convention.

Attention answered 4/3, 2014 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.