Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java synchronized blocks

If we have a method:

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()?

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? That is:

  • 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:

  • Can I count on all execution contexts that both threads (Thread1 and Thread2) can be in the method at the same time? For example, Thread2 in the first sync block and Thread1 in the second sync block to achieve concurrency.
  • Will there be some execution flows where only one thread will be in the method (at a time) effectively serializing the whole flow, making it equivalent to public synchronized void doSomething()?
like image 338
Cratylus Avatar asked Nov 30 '22 10:11

Cratylus


2 Answers

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.

like image 42
Toby Avatar answered Dec 11 '22 05:12

Toby


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.

like image 153
Jon Skeet Avatar answered Dec 11 '22 05:12

Jon Skeet