Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to catch InterruptedException for Object.wait() with synchronized block?

As I understand this is very common snippet for multithreading in Java.

boolean loaded = false;
Object lock = new Object();

public void block() {
    synchronized (lock) {
        while(!loaded)
            lock.wait(); // Unhandled exception type InterruptedException
    }
}

and in another thread

public void done () {
    synchronized (lock) {
        loaded = true;
        lock.notify();
    }
}

But I am not sure where I should put try and catch, I can surround whole synchronized block or only lock.wait()? What is rule of thumb and does it really matter?

For handling is it okay to call Thread.currentThread().interrupt() in this situation?

like image 262
Nikolay Kuznetsov Avatar asked Jan 09 '13 12:01

Nikolay Kuznetsov


People also ask

Why must wait () always be in synchronized block?

As Michael Borgwardt points out, wait/notify is all about communication between threads, so you'll always end up with a race condition similar to the one described above. This is why the "only wait inside synchronized" rule is enforced.

Why wait () notify () and notifyAll () methods have to be called from a synchronized method or block?

The wait(), notify(), and notifyAll() methods should be called for an object only when the current thread has already locked the object's lock. This point sometimes goes unnoticed because programmers are used to calling these methods from within synchronized methods or blocks. Otherwise, you will get "java.

Why wait method throws InterruptedException?

An InterruptedException is thrown when a thread is interrupted while it's waiting, sleeping, or otherwise occupied. In other words, some code has called the interrupt() method on our thread. It's a checked exception, and many blocking operations in Java can throw it.

How do I resolve InterruptedException?

In these cases you should catch the InterruptedException and restore the interrupt status by calling the interrupt() method on the currentThread so the code higher up the call stack can see that an interrupt was issued, and quickly return from the method.


Video Answer


2 Answers

You might want to consider the article by Brian Goetz: Java theory and practice: Dealing with InterruptedException

In general, if you don't know what to do then don't do anything but let a caller code know that this method can be interrupted while waiting on a lock. You can do this by adding throws InterruptedException to a method signature.

If for some reason you are forced to add a try/catch block and handle the exception then Thread.currentThread().interrupt() will do but re-throwing it can be as suitable.

like image 128
Andrey Taptunov Avatar answered Sep 26 '22 18:09

Andrey Taptunov


But I am not sure where I should put try and catch, I can surround whole synchronized block or only lock.wait()? What is rule of thumb and does it really matter?

lock.wait() is the only line that can throw an exception in your block method. So whether you put your try/catch around the wait or include the whole method body does not make a difference from an execution perspective (assuming you exit the loop in both cases of course - if you want to continue looping then the try/catch block should obviously be within the loop).

In other words it is only a matter of style - see this other discussion. I personally think this is more readable:

try {
    synchronized (lock) {
        while (!loaded) {
            lock.wait(); // Unhandled exception type InterruptedException
        }
    }
} catch (InterruptedException e) {
    //to ignore me or not to ignore me, that is the question
    Thread.currentThread().interrupt();
}

For handling is it okay to call Thread.currentThread().interrupt() in this situation?

In the first example below, it is okay to catch the InterruptedException and exit your loop without re-interrupting the thread, because in any case the run method will exit and the thread will die:

new Thread(new Runnable() {

    @Override
    public void run() {
        block();
    }
}).start();

In the second example below, you certainly should re-interrupt the thread to let the run method know whether the reason why block() exited is that loaded became true or that it got interrupted:

public void run() {
    while(!Thread.currentThread().isInterrupted()) {
        loaded = false;
        System.out.println("Launching data load");
        block(); //if false has become true, loop, if interrupted, exit
    }
}

If you don't know how the method will be used, good manners suggest that you should re-interrupt the thread.

like image 22
assylias Avatar answered Sep 26 '22 18:09

assylias