7

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?

Nikolay Kuznetsov
  • 9,467
  • 12
  • 55
  • 101
  • 1
    A) If your thread has received interruption, the most reasonable thing is to call Thread.currentThread().interrupt() and exit. B)You should use high level synchronization primitives - Queues for example C) You should use notifyAll instead of notify D)you should read some book about multithreading like Java Concurrency In Practice by Goetz – Boris Treukhov Jan 09 '13 at 12:07
  • personally when i use these mechanisms (see comment by @Boris Treukhov above) i place the catch immediately around the wait() call – radai Jan 09 '13 at 12:10
  • @BorisTreukhov, can you elaborate on this "But I'm not sure that putting checked exception on all methods in the stack is the best solution." I don't quite get what it means – Nikolay Kuznetsov Jan 09 '13 at 12:30
  • Andrey's answer is correct, but I think that propagating exception with **throws** keyword is not *always* the best choice because you may want to execute some shutdown logic(I mean something beyond just closing the resources which is done in **finally** or in **try-with** construction) - the problem is that finally is reserved for other exceptional situations(not only interrupted exceptions) and some logic does not fit there very well - so the client code(and its flow) will less readable. – Boris Treukhov Jan 09 '13 at 13:06
  • Just to rephrase - when you're developing a synchronization primitive, you can't do anything other then propagating the exception(the primitive does not have any additional logic), but when you're writing some code with multiple threads, using the propagation with **throws** will force you to design your logic around catching the InterruptedException - but the InterruptedException is the thing that likely occurs only when JVM shutdowns. Yes, there are some situations when designing the program around the exception is OK(for example TimeoutException) but I think it is not a default solution. – Boris Treukhov Jan 09 '13 at 13:35

2 Answers2

6

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.

Thomas Keller
  • 5,933
  • 6
  • 48
  • 80
Andrey Taptunov
  • 9,367
  • 5
  • 31
  • 44
  • Yes, I have bookmarked this article before writing the question. But my main question is in bold. – Nikolay Kuznetsov Jan 09 '13 at 12:11
  • @NikolayKuznetsov it does not really matter, the changes in the program flow caused by exception have nothing to do with multithreading. What's important is that the interruption status should not be lost. But I'm not sure that putting checked exception on all methods in the stack is the best solution. P.S. Another thing that calling notify() instead of notifyAll() always requires some reasoning about safety. – Boris Treukhov Jan 09 '13 at 12:23
3

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.

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783