Java: How do I catch InterruptedException on a thr

2019-04-28 07:46发布

问题:

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.)

回答1:

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.



回答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().



回答3:

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



回答4:

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


回答5:

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