The situation is the following:
The question: Do I have to make all variables of this class volatile or not?
Concerns:
Note: I am aware about builder pattern, but I cannot apply it there for several other reasons :(
EDITED: As I feel two answers from Mathias and axtavt do not match very well, I would like to add an example:
Let's say we have a foo
class:
class Foo {
public int x=0;
}
and two threads are using it as described above:
// Thread 1 init the value:
Foo f = new Foo();
f.x = 5;
values.add(f); // Publication via thread-safe collection like Vector or Collections.synchronizedList(new ArrayList(...)) or ConcurrentHashMap?.
// Thread 2
if (values.size()>0){
System.out.println(values.get(0).x); // always 5 ?
}
As I understood Mathias, it can print out 0 on some JVM according to JLS. As I understood axtavt it will always print 5.
What is your opinion?
-- Regards, Dmitriy
Put the assignment in a synchronized block.
If you write volatile variable from multiple threads without using any synchronized constructs, you are bound to get data inconsistency errors. Use volatile variables without synchronization in case of single write thread and multiple read threads for atomic operations.
In Java, threads doesn't cache any object or variable, they just have a reference to an instance of an object. Talking about thread cache memory is more like talking about operative systems threads...
In this case you need to use safe publication idioms when making your object available to other threads, namely (from Java Concurrency in Practice):
- Initializing an object reference from a static initializer;
- Storing a reference to it into a volatile field or AtomicReference;
- Storing a reference to it into a final field of a properly constructed object; or
- Storing a reference to it into a field that is properly guarded by a lock.
If you use safe publication, you don't need to declare fields volatile
.
However, if you don't use it, declaring fields volatile
(theoretically) won't help, because memory barriers incurred by volatile
are one-side: volatile write can be reordered with non-volatile actions after it.
So, volatile
ensures correctness in the following case:
class Foo {
public int x;
}
volatile Foo foo;
// Thread 1
Foo f = new Foo();
f.x = 42;
foo = f; // Safe publication via volatile reference
// Thread 2
if (foo != null)
System.out.println(foo.x); // Guaranteed to see 42
but don't work in this case:
class Foo {
public volatile int x;
}
Foo foo;
// Thread 1
Foo f = new Foo();
// Volatile doesn't prevent reordering of the following actions!!!
f.x = 42;
foo = f;
// Thread 2
if (foo != null)
System.out.println(foo.x); // NOT guaranteed to see 42,
// since f.x = 42 can happen after foo = f
From the theoretical point of view, in the first sample there is a transitive happens-before relationship
f.x = 42 happens before foo = f happens before read of foo.x
In the second example f.x = 42
and read of foo.x
are not linked by happens-before relationship, therefore they can be executed in any order.
You do not need to declare you field volatile of its value is set before the start
method is called on the threads that read the field.
The reason is that in that case the setting is in a happens-before relation (as defined in the Java Language Specification) with the read in the other thread.
The relevant rules from the JLS are:
However, if you start the other threads before setting the field, then you must declare the field volatile. The JLS does not allow you to assume that the thread will not cache the value before it reads it for the first time, even if that may be the case on a particular version of the JVM.
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