I want to write a simple thread-safe class that could be used to set or get an Integer value.
The easiest way is to use the synchronized keyword:
public class MyIntegerHolder {
private Integer value;
synchronized public Integer getValue() {
return value;
}
synchronized public void setValue(Integer value) {
this.value = value;
}
}
I could also try using volatile:
public class MyIntegerHolder {
private volatile Integer value;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
Is the class with the volatile keyword thread-safe?
Consider the following sequence of events:
It follows from the Java Language Specification that
but I don't see how it could follow from the specification that "1" happens-before "2" so I suspect that "1" doesn't happen-before "2".
I suspect the thread C may read 7 or 5. I think the class with the volatile keyword is not thread-safe and the following sequence is also possible:
Am I correct in assuming that MyIntegerHolder with volatile is not thread-safe?
Is it possible to make a thread-safe Integer holder by using AtomicInteger:
public class MyIntegerHolder {
private AtomicInteger atomicInteger = new AtomicInteger();
public Integer getValue() {
return atomicInteger.get();
}
public void setValue(Integer value) {
atomicInteger.set(value);
}
}
?
Here is a fragment of the Java Concurrency In Practice book:
"Reads and writes of atomic variables have the same memory semantics as volatile variables."
What is the best (preferably non-blocking) way of writing a thread-safe MyIntegerHolder?
If you know the answer, I would like to know why you think it is correct. Does it follow from the specification? If so, how?
Volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread safe. It means that multiple threads can use a method and instance of the classes at the same time without any problem. The volatile keyword can be used either with primitive type or objects.
To make these classes thread-safe, you must prevent concurrent access to the internal state of an instance by more than one thread. Because Java was designed with threads in mind, the language provides the synchronized modifier, which does just that.
To declare a variable volatile, include the keyword volatile before or after the data type in the variable definition.
The answer is, Yes, you can make an array (both primitive and reference type array e.g. an int array and String array) volatile in Java but only changes to reference pointing to an array will be visible to all threads, not the whole array.
The keyword synchronized
is saying that if Thread A and Thread B
want to access the Integer
, they cannot do so simultaneously. A is telling B wait until I'm done with it.
On the other hand, volatile
makes threads more "friendly". They start talking to each other and working together to perform tasks. So when B tries to access, A will inform B of everything it has done until that moment. B is now aware of the changes and can continue its job from where A left of.
In Java, you have Atomic
for this reason, which under the covers use the volatile
keyword, so they are doing pretty much the same thing, but they save you time and effort.
The thing you are looking for is AtomicInteger
, you are right about this. For the operation you are trying to perform this is the best choice.
There are two main uses of `AtomicInteger`:
* As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
* As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.
To answer your question on a general note
It depends on what you need. I'm not saying synchronized
is wrong and volatile
is good, otherwise the nice Java people would have removed synchronized
a long time ago. There is no absolute answer, there are a lot of specific cases and usage scenarios.
A few of my bookmarks:
Concurrency tips
Core Java Concurrency
Java concurrency
Update
From the Java Concurrency specification available here:
Package java.util.concurrent.atomic
A small toolkit of classes that support lock-free thread-safe programming on single variables.
Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.
The memory effects for accesses and updates of atomics generally follow the rules for volatiles:
get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.
Also from Here
The Java programming language volatile
keyword:
(In all versions of Java) There is a global ordering on the reads and writes to a volatile variable. This implies that every thread accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value. (However, there is no guarantee about the relative ordering of volatile reads and writes with regular reads and writes, meaning that it's generally not a useful threading construct.)
If you need only get / set on a variable it is enough to declare it volatile like you did. If you check how AtomicInteger set / get work you will see the same implementation
private volatile int value;
...
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
but you cannot increment a volatile field atomically this simple. This is where we use AtomicInteger.incrementAndGet or getAndIncrement methods .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With