This seems a pretty basic issue, but I cannot find a clear confirmation.
Let's say I have a class properly synchronized in itself:
public class SyncClass {
private int field;
public synchronized void doSomething() {
field = field * 2;
}
public synchronized void doSomethingElse() {
field = field * 3;
}
}
If I need to have a reference to an instance of that class, shared between threads, I do still need to declare that instance volatile or final, am I right? As in:
public class MainClass { // previously OuterClass
public static void main(String [ ] args) {
final SyncClass mySharedObject = new SyncClass();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomething();
}
}).start();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomethingElse();
}
}).start();
}
}
Or, if mySharedObject
cannot be final, because its instantiation depends on some other conditions (interaction with GUI, info from socket, etc.), not known beforehand:
public class MainClass { // previously OuterClass
public static void main(String [ ] args) {
volatile SyncClass mySharedObject;
Thread initThread = new Thread(new Runnable() {
public void run() {
// just to represent that there are cases in which
// mySharedObject cannot be final
// [...]
// interaction with GUI, info from socket, etc.
// on which instantation of mySharedObject depends
if(whateverInfo)
mySharedObject = new SyncClass();
else
mySharedObject = new SyncClass() {
public void someOtherThing() {
// ...
}
}
}
});
initThread.start();
// This guarantees mySharedObject has been instantied in the
// past, but that still happened in ANOTHER thread
initThread.join();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomething();
}
}).start();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomethingElse();
}
}).start();
}
}
Final or volatile are mandatory, the fact that MyClass
synchronizes the access to its own members, does NOT exempt to take care in ensuring that the reference is shared among threads. Is that right?
Differences with Difference between volatile and synchronized in Java
1- The referred question is about synchronized and volatile as alternatives, for the same field/variable, my question is about how to correctly use an already properly synchronized class (i.e. synchronized has been choosen), considering implications needed to be considered by the caller, possibly using volatile/final on a reference of an already synchronized class.
2- In other words, the referred question/answers are about locking/volatile THE SAME OBJECT, my question is: how can I be sure different threads actually SEE THE SAME OBJECT? BEFORE locking/accessing it.
When the first answer of referred question refers explicitly to a volatile reference, it's about an immutable object without synchronization. The second answer limits itself to primitive types. I DID find them useful (see below), but not complete enough to shed any doubts on the case I'm giving here.
3- The referred answers are very abstract and scholarly explanations to a very open question, with quite no code at all; as I stated in the introduction I need to a clear confirmation to actual code referring a specific, while quite common, issue. They're related, sure, but just as a text book is related to a specific problem. (I actually read it before opening this question, and find it useful, yet I still need to discuss a specific application.) If text books resolved all problems/doubts people may have applying them, we probably wouldn't need stackoverflow at all.
Consider that, in multithreading, you cannot "just try it out", you need a proper understanding and be sure of details, because race conditions can go right a thousand times and then go horribly wrong the thousand + 1 time.
SyncClass
orMyClass
? You need to be consistent :) – Tourneurvolatile
keyword on local variables, in the way it is used onmySharedObject
in your third example. It can only go on fields. Is your intention thatmySharedObject
should be a field onMainClass
? – Roti