简体   繁体   中英

Do we need to make a field 'volatile', if Thread1 enters sync block, updates it, is still inside the sync block, Thread2 outside of sync reads field?

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.

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM