Effective Java - Item 66 (2nd Edition) states
In fact, synchronization has no effect unless both read and write operations are synchronized.
Suppose I have an object which is being updated by one thread and read by another thread. Synchronization on the read thread is needed for communication purpose, because as stated
In other words, the synchronization on these methods is used solely for its communication effects, not for mutual exclusion.
But if the write is performed by a single thread, why can't we get away without using synchronised during write?
Because of how happens-before works in Java Memory Model. To allow thread2 to see a new value of variable written by thread1 you need to establish happens-before relationship between this write and read (https://www.logicbig.com/tutorials/core-java-tutorial/java-multi-threading/happens-before.html). One of the ways to do it is to use synchronization (synchronized blocks/methods, volatile, AtomicXXX) because releasing a lock always happens before acquiring of the same lock, write to volatile variable happens before subsequent read of the same volatile variable. And AtomicXXX.set() happens before AtomicXXX.get() for the same variable.
Related
Is the volatile modifier required when working with locks to guarantee memory visibility?
Trying to fully understand concurrency, memory visibility and execution control I came across several sources saying that variables updated in synchronized blocks do not require the field to be volatile (mostly no sources given and actually one page saying synchronized methods and volatility fields need to be used in conjunction).
When approaching the jls chapter 17.4.5 I found:
Two actions can be ordered by a happens-before relationship. If one action
happens-before another, then the first is visible to and ordered before the second.
Is this the section which says that subsequent synchronized method calls guarding the same variable variable will ensure it to be visible to the second thread? If this is the case does the same hold true for locks since we can also guarantee an order?
On the other hand what happens when suddenly we have write locks allowing 2 threads to access the field. Does the entire construct collapse and threads are never guaranteed to updated their cache even in the event if the variable is unlocked?
In short code
int field; //volatile not needed because we have a definite happens-before relationship
Lock lock;
void update(){
//No matter how many threads access this method they will always have
//the most up to date field value to work with.
lock.lock()
field *= 2;
lock.unlock();
}
From the API documentation for Lock:
https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/Lock.html
All Lock implementations must enforce the same memory synchronization
semantics as provided by the built-in monitor lock, as described in
Chapter 17 of The Java™ Language Specification:
A successful lock operation has the same memory synchronization effects as a successful Lock action.
A successful unlock operation has the same memory synchronization effects as a successful Unlock action.
Unsuccessful locking and unlocking operations, and reentrant
locking/unlocking operations, do not require any memory
synchronization effects.
That's a little unclear imo but the gist of it is that yes, Lock is required to work the same way as a monitor (what the synchronized keyword does) and therefore your example does always make the most recent update of field visible without explicitly using the volatile keyword.
P.S. Get Brian Goetz's Java Concurrency in Practice, it explains all of this stuff in a lot more detail. It's basically the bible of all things concurrency in Java.
...and actually one page saying synchronized methods and volatility fields need to be used in conjunction.
You can distill everything you need to know about memory visibility and synchronized blocks down to one simple rule. That is, whatever thread A does to shared variables and objects before it exits from a synchronized (o) {...} block is guaranteed to become visible to thread B by the time thread B enters a synchronized (o) {...} block for the same object, o.
And, as #markspace already said, any implementation of java.util.concurrent.locks.Lock is required to work in the same way.
Is the volatile modifier required when working with locks to guarantee memory visibility?
volatile variable only guarantees memory visibility but not the atomicity. This is one of the main difference between volatile and the synchronized block in Java. So when you use synchronized blocks, variables do not have to be volatile. But If your variable is volatile and performing any compound actions on that variable, then you need to guard the update to the volatile variable with the lock.
Is this the section which says that subsequent synchronized method calls guarding the same variable will ensure it to be visible to the second thread? If this is the case does the same hold true for locks since we can also guarantee an order?
Yes. Because locks will give you both visibility and atomicity.
On the other hand what happens when suddenly we have write locks allowing 2 threads to access the field. Does the entire construct collapse and threads are never guaranteed to updated their cache even in the event if the variable is unlocked?
If you guarding the update to the variable on the same lock only one thread can work on that variable at any given time. So it guarantees consistency. But If you use different locks every time to guard that variable, then more than one thread will modify the variable state and can potentially make the variable state inconsistent. So, in this case, both visibility and atomicity are guaranteed but still, it can lead to inconsistency.
I read this in an upvoted comment on StackOverflow:
But if you want to be safe, you can add simple synchronized(this) {}
at the end of you #PostConstruct [method]
[note that variables were NOT volatile]
I was thinking that happens-before is forced only if both write and read is executed in synchronized block or at least read is volatile.
Is the quoted sentence correct? Does an empty synchronized(this) {} block flush all variables changed in current method to "general visible" memory?
Please consider some scenerios
what if second thread never calls lock on this? (suppose that second thread reads in other methods). Remember that question is about: flush changes to other threads, not give other threads a way (synchronized) to poll changes made by original thread. Also no-synchronization in other methods is very likely in Spring #PostConstruct context - as original comment says.
is memory visibility of changes forced only in second and subsequent calls by another thread? (remember that this synchronized block is a last call in our method) - this would mark this way of synchronization as very bad practice (stale values in first call)
Much of what's written about this on SO, including many of the answers/comments in this thread, are, sadly, wrong.
The key rule in the Java Memory Model that applies here is: an unlock operation on a given monitor happens-before a subsequent lock operation on that same monitor. If only one thread ever acquires the lock, it has no meaning. If the VM can prove that the lock object is thread-confined, it can elide any fences it might otherwise emit.
The quote you highlight assumes that releasing a lock acts as a full fence. And sometimes that might be true, but you can't count on it. So your skeptical questions are well-founded.
See Java Concurrency in Practice, Ch 16 for more on the Java Memory Model.
All writes that occur prior to a monitor exit are visible to all threads after a monitor enter.
A synchronized(this){} can be turned into bytecode like
monitorenter
monitorexit
So if you have a bunch of writes prior to the synchronized(this){} they would have occurred before the monitorexit.
This brings us to the next point of my first sentence.
visible to all threads after a monitor enter
So now, in order for a thread to ensure the writes ocurred it must execute the same synchronization ie synchornized(this){}. This will issue at the very least a monitorenter and establish your happens before ordering.
So to answer your question
Does an empty synchronized(this) {} block flush all variables changed
in current method to "general visible" memory?
Yes, as long as you maintain the same synchronization when you want to read those non-volatile variables.
To address your other questions
what if second thread never calls lock on this? (suppose that second
thread reads in other methods). Remember that question is about: flush
changes to other threads, not give other threads a way (synchronized)
to poll changes made by original thread. Also no-synchronization in
other methods is very likely in Spring #PostConstruct context
Well in this case using synchronized(this) without any other context is relatively useless. There is no happens-before relationship and it's in theory just as useful as not including it.
is memory visibility of changes forced only in second and subsequent
calls by another thread? (remember that this synchronized block is a
last call in our method) - this would mark this way of synchronization
as very bad practice (stale values in first call)
Memory visibility is forced by the first thread calling synchronized(this), in that it will write directly to memory. Now, this doesn't necessarily mean each threads needs to read directly from memory. They can still read from their own processor caches. Having a thread call synchronized(this) ensures it pulls the value of the field(s) from memory and retrieve most up to date value.
In Java, the volatile keyword is for direct read and write from main memory so that reads or writes won't be lost if multiple threads are accessing a variable.
Without using volatile, is there any other way to achieve this functionality? I came across this question but couldn't figure out a solution.
Basically, if you want to safely access a non-volatile variable from multiple threads, you need to surround all read/write access to the variable with synchronized blocks that use a shared monitor. Read access to volatile variables (in general) need not be synchronized, because each read operation is guaranteed to see the last write to the variable by any thread.
It is important to notice that using volatile fields alone does not eliminate the need for synchronization when you e.g. need to atomically read a value of a variable, followed by a write to the same variable. A common use case for this is incrementing a counter. As #Louis Wasserman suggests, for these purposes, classes in the java.util.concurrent.atomic package provide reliable and easy to use methods, such as compareAndSet(...) and incrementAndGet().
The Java Language Specification describes a set of happens-before relationships, and a set of synchronizes-with actions. If one action synchronizes-with a following action, it happens-before. A write is guaranteed to be visible if happens-before a read, in this technical sense.
Writes performed inside a synchronized block are visible to threads that synchronize on that lock afterwards, because release of a lock synchronizes-with acquisition by another thread.
A write to a volatile variable synchronizes-with subsequent reads of that variable, so it is visible.
A number of the utilities in the java.util.concurrent also provide a happens-before relationship. For example, actions taken by a thread before it calls countDown() on a CountDownLatch are visible to threads that return from a call to await() on that latch. Of course, many of these APIs achieve this by using volatile, synchronized themselves.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Difference between volatile and synchronized in JAVA (j2me)
I am a bit confused with the 2 java keywords synchronized and volatile.
To what i understand, since java is a multi-threaded language, and by using the keyword synchronized will force it to be executed in 1 thread. Am i correct ?
And volatile also does the same thing ?
Both volatile and synchronized guarantee visibility, but synchronized also provides atomicity:
if one thread thread reads a volatile variable, it has the guarantee to see the previous writes to that same variable, including if they were done by other threads
synchronized blocks give the same guarantee (provided the write and the read are done holding the same monitor) but also provides atomicity guarantees: all instructions within a synchronized block will look atomic from another thread synchronized on the same lock.
For long and double read and write operation are not atomic.
volatile is a modifier you can put on a variable to make read and write operations atomic (including long and double)
The article Atomic Access got more information about it.
Basically it is for making sure that if one thread changed the value of the variable the rest of the threads will see that change and will not able to read it while its written.
Java multi-threading involves two problems, ensuring that multiple operations can be done consistently, without mixing actions by different threads, and making a change in a variable's value available to threads other than the on doing the change.
In reality, a variable does not naturally exist at a single location in the hardware. There may be copies in the internal state of different threads, or in different hardware caches. Simply assigning to a variable automatically changes its value from the point of view of the thread doing the assignment.
If the variable is marked "volatile" other threads will get the changed value.
"synchronized" also ensures changes become visible. Specifically, any change done in one thread before the end of a synchronized block will be visible to reads done by another thread in a subsequent block synchronized on the same object.
In addition, blocks that are synchronized on the same object are forced to run sequentially, not in parallel. That allows one to do things like adding one to a variable, knowing that its value will not change between reading the old value and writing the new one. It also allows consistent changes to multiple variables.
The best way I know to learn what is needed to write solid concurrent code in Java is to read Java Concurrency in Practice
Essentially, volatile is used to indicate that a variable's value will be modified by different threads.
Synchronized is a keyword whose overall purpose is to only allow one thread at a time into a particular section of code thus allowing us to protect, for example, variables or data from being corrupted by simultaneous modifications from different threads.
It is as complicated as described lengthy in Java Memory Model.
Synchronized means that only one thread can access the method or code block at a given time.
Volatile handles the communication between threads. Here is a nice explanation: http://jeremymanson.blogspot.be/2008/11/what-volatile-means-in-java.html
Volatile keyword will make every thread to read or write as an atomic operation in memory location. If you do not use volatile, that variable may be cached by threads, and threads may be reading/writing cached copy instead of actual copy.
So, while working on something that was having locking issues, a question came to me. Do objects that only can be accessed from a single thread require locks or synchronization at all?
For example, given Thread1, Thread2, and Thread3, along with Buffer1, Buffer2, Buffer3, where each buffer is instanced as a thread is created, meaning that Thread1 will only ever access Buffer1, and the same for Thread2 and Buffer2, along with Thread3 and Buffer3. Thread1 will never touch Buffer2 or Buffer3. While adding/removing/modifying bytes in the stream, are locks needed?
No, You wont need any locks in this case. Locking and synchronization is only required when any resource is being shared between multiple threads.
If you go ahead and add synchronization on the private instance of that buffer then still it wont make any difference as there will be no thread waiting to acquire locks, The only one locking and releasing the buffer will be the owner thread.
1. When more than one thread try to access an object, then locking becomes necessary.
2. Moreover classes when developed needs to be thread safe, if concurrent access by threads is possible.
3. A class is said to be thread safe, it if behaves correctly in the presence of interleaving and scheduling of the underlying OS , without any synchronization mechanism from the client.
4. Locking the resources can cause overhead, prevents concurrent access, and bottle neck situations.
Only when two or more threads need to access a shared object you need to worry about locking.
No. This strategy for ensuring thread-safety is generally referred to as confinement.
Confinement relies on encapsulation techniques to ensure that multiple threads cannot access an object. "Concurrent Programming in Java" by Doug Lea has good chapter on the details of confinement and its strengths and weaknesses compared to other exclusion techniques.
Paraphrasing from Lea, in general there are 4 conditions needed for confinement of a reference r, to an object x, within a method m:
m cannot pass r as an argument to another method.
m cannot pass r as a return value.
m cannot record r in a field (instance or static) that is accessible from another thread.
m cannot may not let any other references escape (via 1-3) that may be traversed to r.
From what I remember from my studies, if you are using a private buffer for every thread you should not worry about locking it to avoid concurrent access, since you don't have any.
If no-one is reading the buffer apart from the creator, it could do whatever he wants on it without worrying that someone else is reading or writing it. so you should be fine
But you have to remember that a thread can be interrupted at any time, so your internal buffer can be in a inconsistent state. (this shouldn't be a problem since you are accessing only sequentially from the same thread)
Locks are not needed unless threads are concurrently using the same data structure.
Hence if different data structures are used by each thread, your code is guaranteed to be thread safe.
Incidentally, this is one of the main reasons why the key Java collection classes like java.util.ArrayList are not thread safe: making them thread safe would add a performance overhead which you shouldn't have to pay for if you don't need, and in a lot of cases you don't need it because you can ensure in some other way that only one thread accesses the ArrayList at once.