Java: How do I catch InterruptedException on a thread, when interrupted by another thread?
Asked Answered
H

5

6

I'm developing a multithreaded application to make connections to external servers - each on separate threads - and will be blocked until there is input. Each of these extends the Thread class. For the sake of explanation, let's call these "connection threads".

All these connection threads are stored in a concurrent hashmap.

Then, I allow RESTful web services method call to cancel any of the threads. (I'm using Grizzly/Jersey, so each call is a thread on its own.)

I retrieve the specific connection thread (from the hashmap) and call the interrupt() method on it.

So, here is the question, within the connection thread, how do I catch the InterruptedException? (I'd like to do something when the connection thread is stopped by an external RESTful command.)

Halfbeak answered 1/9, 2012 at 19:15 Comment(4)
Well, AFAIK, when a thread throws InterruptedEx. it will propagate up to the thread that started the exception throwing thread. It is at that parent thread that you can catch the IE.Headmaster
I just did an experiment to surround the code that start the connection thread, and the compiler warns that the InterruptedException is not thrown.Halfbeak
Further, the parent thread that started those connection threads does not go into a wait or sleep state, so it means (or at least I think) it cease to exist after it has started all those child threads.Halfbeak
"Interrupting a thread that is not alive need not have any effect". @spec JSR-51Bruell
C
10

So, here is the question, within the connection thread, how do I catch the InterruptedException?

You can not. Since if your thread is blocked on a read I/O operation it can not be interrupted. This is because the interrupt just sets a flag to indicate that the thread has been interrupted. But if your thread has been blocked for I/O it will not see the flag.
The proper way for this is to close the underlying socket (that the thread is blocked to), then catch the exception and propagate it up.
So since your connection threads extend Thread do the following:

@Override  
public void interrupt(){  
   try{  
      socket.close();  
   }  
   finally{  
     super.interrupt();  
   }  
}   

This way it is possible to interrupt a thread blocked on the I/O.

Then in your run method do:

@Override  
public void run(){  

    while(!Thread.currentThread().isInterrupted()){    
       //Do your work

    }  
}    

So in your case don't try to catch an InterruptedException. You can not interrupt the thread blocked on I/O. Just check if your thread has been interrupted and facilitate the interruption by closing the stream.

Colitis answered 1/9, 2012 at 19:28 Comment(0)
J
2

the problem it is with blocking.

Hoverer, try this code, maybe it will help you:

try{
 yourObject.read();
}catch(InterruptedException ie){
// interrupted by other thread
}
catch(Exception ex){
// io or some other exception happent
}

your read method, should check if there is available buytes at socket for eg, if there are than read it, othervise go to speel mode. When is sleeping than is available the wake up (InterruptedException) at pur socket read ( whatever read have you) it will be blocked. Some API has a value to max waiting, eg 5 sec 60 sec, if nothing o read than it will be next code executed.

class MyReadingObject
{
   public read() throws InterruptedException{
      while(shouldIread){
        if(socket.available() > 0){
           byte[] buff = new byte[socket.avaialble()]
           socket.read(buff);
           return;
        }
        else{
           Thread.currentThread.sleep(whateverMilliseconds);
        } 
     }
  }
}

something like that, but with error handling and some design patterns

Jaunitajaunt answered 1/9, 2012 at 19:24 Comment(3)
I tried something like this, the problem is the "yourObject.read()" does not throw the InterruptedException. The compiler will show an error that no where in the code throws that exception and refuse to compile.Halfbeak
I see I got downvoted, I should reconsider how much time I will waste here. thanks all. Be helpfull, good luck!Jaunitajaunt
Not sure who downvoted you but I have upvoted you because I don't think a down-vote was deserved. I guess the downvote was due to spelling errors/syntax errors in your code?Highspeed
T
2

When you call Thread.interrupt() on some thread, what happens is that 'interruption' flag is set for that thread. Some methods do check this flag (by Thread.interrupted() or Thread.isInterrupted()) and throw InterruptedException, but usually only methods that can block do that. So there is no guarantee that InterruptedException will ever be thrown in interrupted thread. If you don't call any method that throws InterruptedException, there is no point in catching that exception, since it will not be thrown at all. However you can always check if your thread was interrupted by calling Thread.isInterrupted().

Tarton answered 1/9, 2012 at 19:28 Comment(1)
very true, you need to call the mycontroller.getReadingThread().interrupt();Jaunitajaunt
H
1

Calling interrupt() on a thread doesn't stop it, it just switches on the interrupt flag. It's the responsibility of the code to handle the change in the interrupt status of the thread in consideration and act accordingly. If you are performing a blocking operation in that thread, you are pretty much SOL because your thread is "blocking" on the read. Have a look at the answer which I posted here. So basically, unless you are looping over stuff or periodically checking some flags inside that thread, you have no way of breaking out without closing sockets or stuff like that.

One solution here is to "explicitly" expose the underlying connection object and call close() on it, forcing it to throw some sort of exception, which can be then handled in the threaded code. Something like:

class MyAction extends Thread implements Disposable {

  public void doStuff() {
    try {
      byte[] data = this.connection.readFully();
  } catch (InterruptedException e) {
    // possibly interrupted by forceful connection close    
  }

  @Override
  public void dispose() {
    this.connection.close();
  }
}

// Elsewhere in code
MyAction action = conMap.get("something");
action.dispose();
Highspeed answered 1/9, 2012 at 19:29 Comment(0)
S
-2

Use a try-catch like so:

try {
    //code
} catch ( InterruptedException e) {
    //interrupted
}

I think that should do the trick, you could also keep a boolean variable on whether to exit, so they would check that variable, if it's true, stop

Supercilious answered 1/9, 2012 at 19:24 Comment(1)
Where do I put this? In the run() method? - the compiler will say the code does not throw the InterruptedException and will not compile.Halfbeak

© 2022 - 2024 — McMap. All rights reserved.