Let's say we have 'class A' which has a data member 'var'.
class A
{
int var;
method()
{
read(var);
synchronized block
{
update var here;
}
}
Let's say Thread 1 acquires the lock and enters the synchronized block. It updates the field value 'var'. Let's say the field value is cached in the processor's core by the Thread. It updates the value in the cache.
Now thread 2 starts running, enters method(), and reads field value 'var'.
Wil thread 2, surely get the updated value? Does synchronize makes sure thread 2 will get updated value even when Thread 1 has not exited Synchronized. In this case, do we need to make 'var' volatile?
PS - Everything is happening on the same object.
CodePudding user response:
If you would not make 'var' volatile, then there is no happens-before edge between writing and reading 'var'. So you have a data race on your hands and weird things can happen like the compiler messing things up.
So in short: make it volatile (or make sure you read 'var' using the same lock).
CodePudding user response:
Does synchronize makes sure thread 2 will get updated value
No. synchronized
doesn't do anything for a thread if the thread does not enter a synchronized
block. The way to think about synchronized
is this: Whatever one thread does before it leaves a synchronized block is guaranteed to become visible to some other thread by the time the second thread subsequently* enters a block that is synchronized
on the same lock object.
For a single int
variable, you could make it volatile
instead. volatile
makes a guarantee similar to the guarantee of synchronized
: Whatever one thread does before it updates a volatile
variable is guaranteed to become visible to some other thread by the time the second thread subsequently* reads the same volatile
variable.
* Edit: I added "subsequently" to make it clear that neither synchronized
nor volatile
is sufficient to ensure that the threads will access var
in some particular order. If you wish to ensure that thread 2 will not try to read var
until after thread 1 has assigned it, then you will have to use some other means† to coordinate their activity. Correct use of synchronized
or volatile
only can ensure that IF thread 1 updates var
before thread 2 examines it, then thread 2 will see the update.
† There are many "other means." One example is a Semaphore
. Thread 1 could release()
a permit to the semaphore after it updates var
, and thread 2 could acquire()
the permit before it reads var
. The acquire()
call would cause thread 2 to wait if it arrived at the semaphore before thread 1 had done its job.