Are empty synchronized blocks optimized out by Java compiler? - java

Suppose somewhere in my code I write an empty synchronized block:
synchronized(obj){
//No code here
}
So as the synchronized block does not contain any code, will JIT compiler optimize that out by not locking on obj as it will be of no use?
Java compiler does similar tricks such as Lock coarsening but will this synchronized block be also optimized out?
EDIT:
As per the point made by assylias,
synchronized(new Object()){
//empty block
}
will the JIT compiler now be able to optimize this out, since I am using an Object which doesn't escape my method?

This can't be optimized away on the basis of the Java Memory Model semantics. The lock acquisition-release operation may be replaced by something else, but even an empty synchronized block has consequences on the visibility of actions taken by other threads acquiring the same lock.
Specifically, there is a guarantee that all write actions done by one thread before releasing the lock are visible to the other thread after it acquires the same lock.
Regarding your EDIT
This is a very different case: a lock is obtained on an object which can be proved by escape analysis that no other thread will ever be able to fetch it. In this case it doesn't matter what the contents of the synchronized block are: the point is only in the lock used. The code can look as you posted it, or even like this:
Object o = new Object();
synchronized(o) {
// any operations you like, as long as they don't let o escape the method scope
}
This can be acted upon by the transformation known as lock elision: the JVM can pretend it never saw the synchronized block. This is because the JMM semantics refer only to the cases of acquiring the one and the same lock.

Related

Java - how does Lock guarantee happens-before relationship?

Let's consider the following standard synchronization in Java:
public class Job {
private Lock lock = new ReentrantLock();
public void work() {
lock.lock();
try {
doLotsOfWork();
} finally {
lock.unlock();
}
}
}
I understand, based on Javadoc, that this is equivalent to synchronized block. I am struggling to see how this is actually enforced on the lower-level.
Lock has a state which is a volatile, upon call to lock() it does a volatile read, then upon release it performs a volatile write. How can a write to a state of one object ensure, that none of the instruction of doLotsOfWork, which might touch lots of different objects, will not be executed out of order?
Or imagine that doLotsOfWork is actually substituted with 1000+ lines of code. Clearly the compiler cannot know in advance that there is a volatile somewhere inside the lock, therefore it needs to stop re-ordering the instructions. So, how is happens-before guaranteed for lock/unlock, even though it is built around volatile state of a separate object?
Well, if I understood correctly then your answer is here. volatile writes and reads introduce memory barriers : LoadLoad, LoadStore, etc. that forbid re-orderings. At the CPU level this is translated to actual memory barriers like mfence or lfence (the CPU forces the non-reordering via some other mechanisms too, so you might see something else in the machine code as-well).
Here is a small example:
i = 42;
j = 53;
[StoreStore]
[LoadStore]
x = 1; // volatile store
i and j assignments can be re-ordered between then, but they can not with x=1 or in other words i and j can not go below x.
Same applies to the volatile reads.
For your example every operation inside doLotsOfWork can be re-ordered as the compiler pleases, but it can not be re-ordered with lock operations.
Also when you say that the compiler can not know that there is a volatile read/write, you are slightly wrong. It has to know that, otherwise there would be no other way to prevent those re-orderings.
Also, last note: since jdk-8 you can enforce non re-orderings via the Unsafe that provides ways to that besides volatile.
From Oracle's documentation:
A write to a volatile field happens-before every subsequent read of
that same field. Writes and reads of volatile fields have similar
memory consistency effects as entering and exiting monitors, but do
not entail mutual exclusion locking.
Java Concurrency in Practice states it even more clearly:
The visibility effects of volatile variables extend beyond the value
of the volatile variable itself. When a thread A writes to a volatile
variable and subsequently thread B reads that same variable, the
values of all variables that were visible to A prior to writing to the
volatile variable become visible to B after reading the volatile
variable.
Applied to ReentrantLock it means that everything executed before lock.unlock() (doLotsOfWork() in your case) will be guaranteed to happen before subsequent call to lock.lock(). Instructions inside doLotsOfWork() still can be reordered among themselves. The only thing that is guaranteed here is that any thread which will subsequently acquire the lock calling lock.lock() will see all changes done in doLotsOfWork() before calling lock.unlock().

Non volatile status flag in multi-threaded code

I am a novice when it comes to concurrency and unsure of myself when spotting issues, I was looking through a fairly established code base and found the following code (edited for brevity) which I believe to be susceptible to data races:
public class Example extends Thread {
boolean condition = false;
public void run () {
while (true) {
synchronized (this) {
try {
while( condition ) wait();
}
catch (InterruptedException e) { /*for brevity*/ }
}
// non-blocking computation
}
}
public void setTrue () { condition = true; }
public void setFalse () {
synchronized (this) {
condition = false;
this.notifyAll();
}
}
}
As far as I understand condition must be volatile since even with the synchronized block, the compiler will not issue any memory barriers; if it were a volatile store to condition in setTrue the compiler would issue StoreEnter.
Am I right to believe the above is susceptible to data races? And if so how can I witness the data race through an example (as opposed to simply knowing the guarantees provided by the JMM). A simple test with threads randomly invoking setTrue in a loop doesn't uncover the data race.
Also, I believe the use of notifyAll is overkill here since there is one condition to check and only one thread will ever be waiting on it, right?
Thank you.
As far as I understand condition must be volatile since even with the synchronized block, the compiler will not issue any memory barriers; if it were a volatile store to condition in setTrue the compiler would issue StoreEnter.
That is not correct. When you use a shared variable within a synchronized block, your code will be thread-safe with respect to other threads using the same variable with the same lock. If memory barriers are required, then they will be used.
However, the code you have shown us is is incorrect because the setTrue() method is updating the flag outside of a synchronized block.
Am I right to believe the above is susceptible to data races?
Yea ... sort of. The scenario is as follows:
The condition is false.
Some other thread calls setTrue which sets the condition variable to true in its cache. But since the setTrue method doesn't use synchronized, there is no write barrier, and no flushing to main memory.
The "example" thread fetches the latest committed value from main memory (which is still false), and doesn't wait as it is supposed to do.
Also, I believe the use of notifyAll is overkill here since there is one condition to check and only one thread will ever be waiting on it, right?
It could be replaced with a notify() ... if that is what you mean. But to be honest, it makes no real difference which flavour of notify you use.
You commented:
I meant that the compiler would not consider it necessary to submit a memory barrier in this situation.
Maybe. But the "monitorenter" and "monitorexit" instructions implicitly involve memory barriers.
And:
Wouldn't it also be correct if condition were volatile?
If you are talking about using volatile AND synchronized, then yes it would be correct ... though the volatile would be redundant (assuming that the setTrue bug is fixed.)
If you are talking about volatile only, then no. You can't implement an efficient "wait on a condition variable" with just volatile. The problem is that neither the "read/test/wait" or "write/notify" sequences can be performed atomically; i.e. without the possibility of race-conditions.
And besides, you can't do the equivalent of wait/notify without using a primitive object mutex, or a Lock object.
Am I right to believe the above is susceptible to data races?
Don't think so. condition is unimportant, it only permits the method to avoid waiting. The way it is set is also not important. It doesn't need to be volatile, as it's use is local to one object.
Also, I believe the use of notifyAll is overkill here since there is
one condition to check and only one thread will ever be waiting on it,
right?
NotifyAll is fine, while there is only one thread waiting in the method there may be many other threads waiting on, or waiting for, the thread.

synchronized(this) blocks whole object? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
synchronized block vs synchronized method?
From accepted answer to this question: In Java critical sections, what should I synchronize on?
I learn that
public synchronized void foo() {
// do something thread-safe
}
and:
public void foo() {
synchronized (this) {
// do something thread-safe
}
}
do exactly the same thing. But in first case we make synchronized only one method of object, and in second case we make inaccessible Whole object. So why this two code snippests do same things?
You seem to be mixing things.
Firstly
public synchronized void method() {
}
is equivalent, from a synchronization perspective, to:
public void method() {
synchronized (this) {
}
}
The pros / cons have already been mentioned and the various duplicates give more information.
Secondly,
synchronized(someObject) {
//some instructions
}
means that the instructions in the synchronized block can't be executed simultaneously by 2 threads because they need to acquire the monitor on someObject to do so. (That assumes that someObject is a final reference that does not change).
In your case, someObject happens to be this.
Any code in your object that is not synchronized, can still be executed concurrently, even if the monitor on this is held by a thread because it is running the synchronized block. In other words, synchronized(this) does NOT "lock the whole object". It only prevents 2 threads from executing the synchronized block at the same time.
Finally, if you have two synchronized methods (both using this as a lock), if one thread (T1) acquires a lock on this to execute one of those 2 methods, no other thread is allowed to execute any of the two methods, because they would need to acquire the lock on this, which is already held by T1.
That situation can create contention in critical sections, in which case a more fine grained locking strategy must be used (for example, using multiple locks).
We don't synchronize an object, instead we synchronize a block of code. In the first that block of code is the method itself, while in the second it's the synchronized block.
The object only provides the lock so as to prevent multiple threads from simultaneously entering that block of code. In the first case, the this object (the one on which the method is invoked) will be used implicitly as the lock, while in the second case it doesn't always have to be this object, it could be some other object also.
They do the same thing. The first form is a short-hand for the second form.
One minor difference between the two constructs is this - synchronized blocks are compiled into monitorenter (op-code 0xC2) and monitorexit (op-code 0xC3) instructions.
A synchronized method, when compiled, is distinguished in the runtime constant pool by
the ACC_SYNCHRONIZED flag, which is checked by JVM’s the method invocation instructions. This difference does not have much significance in practice though.
They dont do same things. First part being synched from beginning to end. Second is just synching the block(not whole method). Second one has some flexibility.

Java: How exactly do synchronized operations relate to volatility?

Sorry this is such a long question.
Ive been doing lots of research lately into multi-threading as I slowly implement it into a personal project. However, probably due to an abundance of slightly incorrect examples, the use of synchronized blocks and volatility in certain situations is still a bit unclear to me.
My core question is this: Are changes to references and primitives automatically volatile (that is, performed on the main memory and not a cache) when a thread is inside a synchronized block, or does the read also have to be synchronized for it to work properly?
If so What is the purpose of synchronizing a simple getter method? (see example 1 ) Also, are ALL changes sent to main memory as long as the thread has synchronized on anything? eg if it is sent off to do loads of work all over the place inside a very high level sync will every single change then made be to main memory, and nothing ever to cache, until its unlocked again?
If not Does the change have to be explicitly inside a synchronized block, or can java actually pick up on, for example, uses of the Lock object? (see example 3)
If either Does the synchronized object need to be related to the reference/primitive being changed in any way (eg the immediate object that contains it)? Can I write by syncing on one object and read with another if its otherwise safe? (see example 2)
(please note for the following examples that I know that synchronized methods and synchronized(this) are frowned upon and why, but discussion about that is beyond the scope of my question)
Example 1:
class Counter{
int count = 0;
public synchronized void increment(){
count++;
}
public int getCount(){
return count;
}
}
In this example, increment() needs to be synchronized since ++ is not an atomic operation. As such, two threads incremending at the same time may result in a overall increase of 1 to the count. The count primitive needs to be atomic (eg not long/double/reference), and it is so thats fine.
Does getCount() need to be synchronized here and why exactly? The explanation I have heard the most is that I will have no guarantee whether the count returned will be the pre- or post-increment. However, this seems like the explanation for something slightly different, thats found itself in the wrong place. I mean if I were to synchronize getCount(), then I still see no guarantee - its now down to not knowing the locking order, insead of not knowing whether the actual read happens to be before/after the actual write.
Example 2:
Is the following example threadsafe, if you assume that through trickery not shown here that none of these methods will never be called at the same time? Will count increment in an expected way if its done so using a random method each time, and then be read properly, or does the lock have to be the same object? (btw I fully realise how rediculous this example is but Im more interested in theory than practice)
class Counter{
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private final Object lock3 = new Object();
int count = 0;
public void increment1(){
synchronized(lock1){
count++;
}
}
public void increment2(){
synchronized(lock2){
count++;
}
}
public int getCount(){
synchronized(lock3){
return count;
}
}
}
Example 3:
Is the happens-before relationship simply a java concept, or is it an actual thing built into the JVM? Even though I can guarantee a conceptual happens-before relationship for this next example, is java smart enough to pick it up if its a built in thing? I am assuming it is not, but is this example actually threadsafe? If its threadsafe, what about if getCount() did no locking?
class Counter{
private final Lock lock = new Lock();
int count = 0;
public void increment(){
lock.lock();
count++;
lock.unlock();
}
public int getCount(){
lock.lock();
int count = this.count;
lock.unlock();
return count;
}
}
Yes, the read has to be synchronized as well. This page says:
The results of a write by one thread are guaranteed to be visible to a
read by another thread only if the write operation happens-before the
read operation.
[...]
An unlock (synchronized block or method exit) of a monitor
happens-before every subsequent lock (synchronized block or method
entry) of that same monitor
The same page says:
Actions prior to "releasing" synchronizer methods such as Lock.unlock,
Semaphore.release, and CountDownLatch.countDown happen-before actions
subsequent to a successful "acquiring" method such as Lock.lock
So locks offer the same visibility guarantees as synchronized blocks.
Whether you use synchronized blocks or locks, the visibility is only guaranteed if the reader thread uses the same monitor or lock as the writer thread.
Your Example 1 is incorrect: the getter must be synchronized as well if you want to see the latest value of the count.
Your example 2 is incorrect because it uses different locks to guard the same count.
Your example 3 is OK. If the getter did not lock, you could see an older value of the count. The happens-before is something that is guaranteed by the JVM. The JVM has to respect the rules specified, by flushing caches to the main memory for example.
Try to view it in terms of two distinct, simple operations:
Locking (mutual exclusion),
Memory barrier (cache sync, instruction reordering barrier).
Entering a synchronized block entails both locking and memory barrier; leaving the synchronized block entails unlocking + memory barrier; reading/writing a volatile field entails memory barrier only. Thinking in these terms I think you can clarify for yourself all the question above.
As for Example 1, the reading thread will not have any kind of memory barrier. It's not just between seeing the value before/after read, it's about never observing any change to the var after a thread is started.
Example 2. is the most interesting issue you raise. You are indeed given no guarantees by the JLS in this case. In practice you won't be given any ordering guarantees (it's as if the locking aspect wasn't there at all), but you'll still have the benefit of the memory barriers so you will observe changes, unlike the first example. Basically, this is exactly the same as removing synchronized and tagging the int as volatile (apart from the runtime costs of acquiring locks).
Regarding Example 3, by "just a Java thing" I feel you have generics with erasure in mind, something that only the static code checking is aware of. This is not like that -- both locks and memory barriers are pure runtime artifacts. In fact, the compiler can't reason about them at all.

Is 'synchronized' really just syntactic sugar?

I am new to multithreading, and I wrote this code which prints the numbers 1-10000 by having concurrently running threads increment and print a variable.
Here's the code I'm using:
package threadtest;
public class Main{
static int i=0;
static Object lock=new Object();
private static class Incrementer extends Thread{
#Override
public void run(){
while (true){
synchronized(lock){
if (i>=10000)
break;
i++;
System.out.println(i);
}
}
}
}
public static void main(String[] args) {
new Incrementer().start();
new Incrementer().start();
new Incrementer().start();
new Incrementer().start();
new Incrementer().start();
new Incrementer().start();
}
}
This works - I wrote up a test program to check the output, and the numbers printed are exactly 1-10000 in order.
My question is this: I've heard that synchronized is only syntactic sugar. But I can't seem to achieve a successful result without using it. What am I missing?
synchronized is by no means syntactic sugar for anything. There is no way to work locks in Java without using the synchronized keyword.
Where there is "syntactic sugar" of a sort in locks in Java is that synchronized can apply both to blocks (as you've done it above) and to whole methods. The following two methods are roughly equivalent in semantics:
synchronized void method1() {
// ... do stuff ...
}
void method2() {
synchronized(this) {
// ... do stuff ...
}
}
So why would you want to do the second version instead of the first?
Synchronized method invocations are far slower than plain old method invocations, like by about an order of magnitude. If your synchronized code isn't guaranteed to always execute (say it's in a conditional), then you probably don't want to synchronize the whole method.
Synchronized methods hold locks for longer than synchronized blocks (because of all the method setup/tear down code). The second method above will hold the lock for less time because the time spent setting up and tearing down the stack frame won't be locked.
You can have much finer control over exactly what you're locking if you go with the synchronized blocks.
(Courtesy of starblue) Synchronized blocks can use objects other than this for locking which gives you more flexible locking semantics.
It sounds like your sources are just wrong. The syncrhonized keyword is important to use - and use properly - when writing thread-safe code. And it sounds like your own experiments bear this out.
For more on synchronization in Java:
Java Synchronized Methods
Java Locks and Synchronized Statements
Actually as of Java 5 you (formally) have an alternative set of tools in java.util.concurrent. See here for more details. As detailed in the article the monitor locking model provided at Java's language level has a number of significant limitations and can be difficult to reason about when there are a complex set of interdependent objects and locking relationships making live-lock a real possibility. The java.util.concurrent library offers locking semantics which might be more familiar to programmers who've had experience in POSIX-like systems
Of course, "synchronized" is just syntactic sugar - extremley useful syntactic sugar.
If you want sugar-free java programs, you should be writing directly in java byte code the monitorenter, monitorexit, lock, and unlock operations referenced in VM Specifications 8.13 Locks and Synchronization
There is a lock associated with every object. The Java programming
language does not provide a way to
perform separate lock and unlock
operations; instead, they are
implicitly performed by high-level
constructs that always arrange to pair
such operations correctly. (The Java
virtual machine, however, provides
separate monitorenter and monitorexit
instructions that implement the lock
and unlock operations.)
The synchronized statement computes a
reference to an object; it then
attempts to perform a lock operation
on that object and does not proceed
further until the lock operation has
successfully completed. (A lock
operation may be delayed because the
rules about locks can prevent the main
memory from participating until some
other thread is ready to perform one
or more unlock operations.) After the
lock operation has been performed, the
body of the synchronized statement is
executed. Normally, a compiler for the
Java programming language ensures that
the lock operation implemented by a
monitorenter instruction executed
prior to the execution of the body of
the synchronized statement is matched
by an unlock operation implemented by
a monitorexit instruction whenever the
synchronized statement completes,
whether completion is normal or
abrupt.
A synchronized method automatically
performs a lock operation when it is
invoked; its body is not executed
until the lock operation has
successfully completed. If the method
is an instance method, it locks the
lock associated with the instance for
which it was invoked (that is, the
object that will be known as this
during execution of the method's
body). If the method is static, it
locks the lock associated with the
Class object that represents the class
in which the method is defined. If
execution of the method's body is ever
completed, either normally or
abruptly, an unlock operation is
automatically performed on that same
lock.
Best practice is that if a variable is
ever to be assigned by one thread and
used or assigned by another, then all
accesses to that variable should be
enclosed in synchronized methods or
synchronized statements.
Although a compiler for the Java
programming language normally
guarantees structured use of locks
(see Section 7.14, "Synchronization"),
there is no assurance that all code
submitted to the Java virtual machine
will obey this property.
Implementations of the Java virtual
machine are permitted but not required
to enforce both of the following two
rules guaranteeing structured locking.
Let T be a thread and L be a lock.
Then:
The number of lock operations performed by T on L during a method
invocation must equal the number of
unlock operations performed by T on L
during the method invocation whether
the method invocation completes
normally or abruptly.
At no point during a method invocation may the number of unlock
operations performed by T on L since
the method invocation exceed the
number of lock operations performed by
T on L since the method invocation.
In less formal terms, during a method
invocation every unlock operation on L
must match some preceding lock
operation on L.
Note that the locking and unlocking
automatically performed by the Java
virtual machine when invoking a
synchronized method are considered to
occur during the calling method's
invocation.
Synchronization is one of the most important concepts while programming in multi thread environment.
While using synchronization one has to consider the object over which synchronization takes place.
For example if a static method is to be synchronized then the synchronization must be on the class level using
synchronized(MyClass.class){
//code to be executed in the static context
}
if the block in instance method is to be synchronized then the synchronization must be using an instance of an object which is shared between all the threads.
Most poeple go wrong with the second point as it appears in your code where the synchronization appears to be on different objects rather than a single object.

Categories

Resources