Search code examples
javaandroidconcurrencyandroid-servicejava-threads

Using wait() inside a synchronized block


I stumbled upon a piece of code in an Android Service class that has a synchronized block with a wait statement. The code is as follows:

    public class MyService extends IntentService{

     protected void onHandleIntent(Intent intent){
     synchronized(this){
        try{
           wait(10000);         
           }catch(InterruptedException e){
           e.printStackTrack();
         }
        String message = intent.getStringExtra("Message");
        showMessage(message);
       }
      }
    }

Does the above code means that any number of threads can enter the synchronized block? I know that sleep puts the Thread in a Blocked state. Is this the same with a Thread calling wait()? Basically when I pass a text to the Service, I want the Service to wait for 10 seconds then display the message in the LogCat. I have never used wait() anytime so could anybody explain to me what the above code is doing?


Solution

  • Your statement "any number of threads can enter the synchronized block" is false.

    Theoretically, if one thread is inside the synchronized block, this prevents other threads from entering. Which is not possible in the case of IntentService because IntentService uses a single worker thread to handle the workload.

    Calling wait() is a thread synchronization method, not a delay method. This is different from calling sleep() which just blocks the thread for a specific amount of time. When you call wait() this blocks the thread until another thread calls notify(), which is used to coordinate activities among multiple threads. wait(10000) blocks the thread until either notify() is called from another thread OR until the timeout expires (in this case 10 seconds). So this looks like there should be another thread somewhere which is calling notify() on the IntentService object to wake it up.

    There is an additional complexity here associated with the use of notify() and wait(). In order to call either of these methods, a lock on the object's monitor must first be obtained (by the use of synchronized). This means that calls to wait() and notify() must be within synchronized blocks or within synchronized methods that are synchronized on the object.

    The thread that calls wait() actually releases the lock on the object. This means that the thread is blocked inside a synchronized block/method but it does not have a lock on the object while waiting. Once notify() is called (or the timeout has expired), the thread will regain the lock on the object and continue executing.

    For more information about using notify() and wait() in Java, search for these terms and read about it.


    This code is pretty convoluted if all it is supposed to do is delay 10 seconds and then write a something to logcat. You could just call sleep() instead of wait() which would not require the synchronized statement. However, as another poster noted, if this Service is called very often, this will create a backlog as each and every call to onHandleIntent() will be delayed by 10 seconds and since there is only 1 worker thread, all calls are serialized. Example: a call to startService() is made at 10:00:00, the entry in the logcat will appear at 10:00:10. If another call to startService() is made at 10:00:01, that entry will not appear in the logcat until 10:00:20, because the second call to onHandleIntent() will not happen until 10:00:10.