views:

132

answers:

6

Hi, I want to ask the following: If we have a method e.g.

public void doSomething(){
   synchronized(this){
     //some code processing here
   }
   String temp = "init"; //instead of i++ 
   synchronized(this){
     //some other code processing here
   }
}

is this method equivalent to public synchronized void doSomething()? I mean, is there any reason not to assume that the thread scheduler in some executions would not result in effectively the same flow as synchronizing the whole function? I.e. Thread1 enters the first synchronized block, Thread2 blocks, Thread1 continues with i++ and moves to the second synchronized block while Thread2 remains blocked. As a result thread2 enters the method after thread1 has exited both synchronized blocks All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency, or there will be some execution flows where only 1 thread will be in the method effectively serializing the whole flow making equivalent to public synchronized void doSomething()

Thanks

A: 

This method is not same as making it a synchronized method. The behavior you explained may be seen but can never be guranteed.

Gopi
+2  A: 

In some executions it would have the same flow as synchronizing the whole functions, sure - but for it to be truly equivalent to making the method synchronized, it would have to have the same flow for all executions.

As it is, there's a possibility that another thread will grab the lock (whether for this method or some other code locking on the same monitor) half way through execution. That couldn't happen if the method itself were synchronized, therefore they're not equivalent.

(As an aside, locking on this is generally considered to be bad practice anyway; I can't remember the last time I wrote a synchronized method. I lock on privately held monitors instead, so that I know my code is the only code which can possibly lock on them.)

EDIT: To respond to your edit:

All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency

Absolutely not! It's guaranteed that you won't have two threads both in a synchronized block synchronized on the same monitor.

You have three sections of code: the first synchronized block, the unsynchronized part, and the second synchronized part.

Any number of threads can be executing in the unsynchronized part at a time. For any one instance (because you're synchronizing on this) only one thread can be executing either of the synchronized blocks. If you want to achieve concurrency, you'd have to synchronize on different monitors.

Furthermore, it sounds like you want guarantees of the scheduler letting another thread grab the lock if it was waiting for it. I don't believe there's any such guarantee - a thread executing the first block could release the lock but continue in the same timeslice and re-acquire it before any other threads got in. In some JVMs that may not happen, but I don't believe there's any guarantee around it.

Jon Skeet
Thanks. I will edit my question since I was not clear
All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency, or there will be some execution flows where only 1 thread will be in the method effectively serializing the whole flow making equivalent to public synchronized void doSomething()
@user384706: I've edited my answer accordingly.
Jon Skeet
Thanks you Jon!
+1  A: 

No it's not. For example for the code above

Thread one enters the first sync'd block executes it and exits then is switched out. Thread two enters the first sync'd block executes it increments i then enters the second sync'd block before being switched out. Thread one now cannot continue until Thread two exits the second sync'd block.

This pattern cannot happen if the entire method is sync'd.

Toby
A: 

No, it's not equivalent to synchronized void doSomething() because i++ is not an atomic operation. In fact, it probably does something like

int temp = i; i = i + 1; result = temp

If those operations are not made atomic, then the value of i could be read while it is in a bad state.

Shakedown
You are right. I changed the code example. I should have been more careful in the code example.
+2  A: 

Given that the synchronized keyword is used to implement monitors in Java, the given piece of code cannot be guaranteed to be synchronized.

In reality, is it possible for both the threads in question to complete the first synchronized block, and then execute the statement to increment the value of i, before executing the next block.

I'm assuming that the variable i contains state that is shared between the two threads, in which case the operation is not thread-safe. In order to make the sequence of operations thread-safe you must ensure that the entire sequence is executed by one thread at a time. Executing the individual operations in separate monitors is as good as executing the operations without a monitor; the entire sequence must be guarded by the monitor.

More info at artima.com in the sample chapter from Inside the Java Virtual Machine.

EDIT:

Given the fact that the question now reflects the use of a local String object, the sequence of operations can be considered as thread safe. Each thread creates its own local reference on the stack to the String object; any mutation of the object in one thread, will not affect the other due to the immutable property of String objects (a new String object is created for all practical purposes, when mutation occurs, and therefore state is not truly shared across threads).

Emphasis:

When attempting synchronization of threads, consider the sequence of operations to be thread-safe if access to shared data is made mutually exclusive; that way one thread will not be able to read or write to the shared variables, while the other is performing an operation involving the shared data. Using local variables only, removes any sense of sharing among threads.

Vineet Reynolds
All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency, or there will be some execution flows where only 1 thread will be in the method effectively serializing the whole flow
No, there is no such guarantee. Like I've stated in the answer, Thread1 and Thread2 can exit the first monitor (in a sequence), and perform the unguarded operation (the statement in between the two sync blocks), before one of them enters the second monitor. This runs counter to what you want to achieve - two threads are either inside a monitor or only one of them is executing the method.
Vineet Reynolds
+1  A: 

All I need to know is whether I can count on all execution contexts that both threads (e.g. Thread1 and Thread2) can be in the method at the same time, e.g thread2 in the first sync block and thread1 in the second sync block to achieve concurrency

No! This is never the case. There is only one lock associated with this. By virtue of using the same lock for both synchronized blocks, it is impossible for Thread2 to be in the first synchronized block if Thread1 is in the second synchronized block.

All other answers stating that the method you posted is not the same as synchronizing the whole method are technically correct.

Tim Bender