Is 'synchronized' really just syntactic sugar? - java

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.

Related

Java synchronized method with expensive parameters

I have a synchronized method that appears to be 'using' the synchronization for significantly longer than it should. It looks something like;
public static synchronized void myMethod(MyParameter p) {
//body (not expensive)
}
The call looks like;
myMethod(generateParameter());
Where generateParameter() is known to be a very expensive (takes a long time) call. My thinking is that the mutex on the myMethod class is blocked during the execution of generateParameter() is this what happens? I'm finding it a different problem to debug but this is what appears to be going on.
That can't be it; the generateParameter() call is executed first, and its results are then given as an argument to the myMethod call, which then grabs the mutex.
Is it taking long, or is it indefinitely blocked? (a deadlock)
No it is not what happens.
Method generateParameter is executed before call to myMethod.
In Java, all method arguments are always evaluated before method call.
The specification of method call explains it in detail (thanks to Victor Sorokin).
At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code.
Your code is the same as the one below, except of new variable:
MyParameter p = generateParameter();
myMethod(p);
The thread executing myMethod enters the object's monitor at the beginning of the method and holds it until it exits. Any operations done inside the method are synchronized, but all call parameters are evaluated before the call is made, so generateParameter is not executing inside myMethod's lock window.
If generateParameter has any synchronization on it, though, it could be contending for the same lock, since without an explicit synchronization object the JVM synchronizes on the object whose method is being called.
I strongly suggest profiling the code to determine where it's really getting stuck.
Instead of static synchronized void myMethod(p) its better to use ReadWriteLock for your resources:
MyParameter p = generateParameter();
myMethod(p){
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readWriteLock.readLock().lock();
// multiple readers can enter this section
// if not locked for writing, and not writers waiting
// to lock for writing.
readWriteLock.readLock().unlock();
readWriteLock.writeLock().lock();
// only one writer can enter this section,
// and only if no threads are currently reading.
readWriteLock.writeLock().unlock();
}
"the mutex on the myMethod class is blocked during the execution of generateParameter()"
As far as I know the lock is not acquired until the execution of the generateParameter function ends.

Are empty synchronized blocks optimized out by Java compiler?

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.

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.

Doubt on avoiding liveness failure - discussed in Effective Java

I am refering to page 261 - 262 of Joshua Bloch Effective Java
// Properly synchronized cooperative thread termination
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
Note that both the write method
(requestStop) and the read method
(stop- Requested) are synchronized. It
is not sufficient to synchronize only
the write method! In fact,
synchronization has no effect unless
both read and write operations are
synchronized.
Joshua's example is synchronized on this. However My doubt is that, must synchronized be acted on the same object? Say, if I change the code to
private static void requestStop() {
synchronized(other_static_final_object_monitor) {
stopRequested = true;
}
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
will this still able to avoid liveness failure?
That's is, we know grabbing monitor for a same object during read/write can avoid liveness failure (According to Joshua Bloch's example). But how about grabbing monitor for different object during read/write?
I don't believe it's guaranteed, although I wouldn't be surprised if it actually was okay in all existing implementations. The Java Language Specification, section 17.4.4 states this:
An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where subsequent is defined according to the synchronization order).
I believe that all the safety of reading/writing shared variables within locks stems from that bullet point in the spec - and that only specifies anything about a lock and an unlock action on a single monitor.
EDIT: Even if this did work for a single variable, you wouldn't want to use it for multiple variables. If you update multiple variables while holding a monitor and only read from them when holding a monitor, you can ensure that you always read a consistent set of data: nothing's going to write to variable Y before you've read that but after you've read variable X. If you use different monitors for reading and writing, that consistency goes away: the values could be changed at any time while you're reading them.
Possibly, but there are no guarantees and it could be highly platform dependant. In your case there is no real test for liveliness so if the value is a few milli-seconds late your application will appear to work correctly anyway. The application will stop eventually without any synchronized and you may not see then difference.
The problem with memory consistency errors is I have seen examples where something can be updated correctly in a test 1 billion times and then fail when there is a different program running on the system. This is why guaranteed behaviour is more interesting.
According to the The Java Language Specification,
"We say that a read r of a variable v is allowed to observe a write w to v if, in the happens-before partial order of the execution trace:
r is not ordered before w (i.e., it is not the case that hb(r, w), and
there is no intervening write w' to v (i.e., no write w' to v such that hb(w, w') and hb(w', r).
Informally, a read r is allowed to see the result of a write w if there is no happens-before ordering to prevent that read."
This means that unless there is some explicit synchronization action that causes multiple threads to interleave their actions in some predictable way (i.e. there's a good happens-before relationship defined on their actions), then a thread is allowed to see pretty much any value of a variable at any point where it was written to.
If you synchronize on multiple different objects, there is no happens-before relationship connecting the reader and the writer. This means that the reading thread can keep seeing whatever value it wants for the stopRequested variable, which could either be the first value forever, or the new value as soon as its updated, or something delightfully in-between the two.
Theoretically it's wrong. Per lang spec v3, the background thread may not see the update.
Practically it'll work. VM just can't be that smart to optimize to such a degree. (In older version of Java, which has threading spec worded differently, it is possible that your suggestion is correct even in theory.)
In any case, don't do it.
If you use a different monitor, there is no synchronization. No other code is requesting the monitor of this or other_static_final_object_monitor.
Using a static object to synchronize is only useful, if you want to synchronize across classes and within methods.
Also, NEVER use a String as a lock/monitor. Always use something like this:
static final Object LOCK = new Object();

Categories

Resources