简体   繁体   English

Java:当被另一个线程中断时,如何在线程上捕获InterruptedException?

[英]Java: How do I catch InterruptedException on a thread, when interrupted by another thread?

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. 其中每个都扩展了Thread类。 For the sake of explanation, let's call these "connection threads". 为了便于解释,我们称之为“连接线程”。

All these connection threads are stored in a concurrent hashmap. 所有这些连接线程都存储在并发hashmap中。

Then, I allow RESTful web services method call to cancel any of the threads. 然后,我允许RESTful Web服务方法调用取消任何线程。 (I'm using Grizzly/Jersey, so each call is a thread on its own.) (我正在使用Grizzly / Jersey,所以每次调用都是一个线程。)

I retrieve the specific connection thread (from the hashmap) and call the interrupt() method on it. 我检索特定的连接线程(来自hashmap)并在其上调用interrupt()方法。

So, here is the question, within the connection thread, how do I catch the InterruptedException? 那么,这是一个问题,在连接线程中,我如何捕获InterruptedException? (I'd like to do something when the connection thread is stopped by an external RESTful command.) (当外部RESTful命令停止连接线程时,我想做点什么。)

So, here is the question, within the connection thread, how do I catch the InterruptedException? 那么,这是一个问题,在连接线程中,我如何捕获InterruptedException?

You can not. 你不能。 Since if your thread is blocked on a read I/O operation it can not be interrupted . 由于如果您的线程在读取I / O操作中被阻止,则无法interrupted This is because the interrupt just sets a flag to indicate that the thread has been interrupted. 这是因为interrupt只是设置一个标志来指示线程已被中断。 But if your thread has been blocked for I/O it will not see the flag. 但是如果您的线程已被I / O阻塞,它将看不到该标志。
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: 因此,由于您的连接线程extend Thread请执行以

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

This way it is possible to interrupt a thread blocked on the I/O. 这样就可以中断I / O上阻塞的线程。

Then in your run method do: 然后在你的run方法中执行:

@Override  
public void run(){  

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

    }  
}    

So in your case don't try to catch an InterruptedException . 所以在你的情况下不要试图catch InterruptedException You can not interrupt the thread blocked on I/O. 您无法中断I / O上阻塞的线程。 Just check if your thread has been interrupted and facilitate the interruption by closing the stream. 只需检查您的线程是否已被中断,并通过关闭流来促进中断。

the problem it is with blocking. 阻塞的问题。

Hoverer, try this code, maybe it will help you: Hoverer,试试这个代码,也许它会帮助你:

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. 当睡眠时间超过可用时,在pur套接字读取唤醒(InterruptedException)(无论读取什么)它将被阻止。 Some API has a value to max waiting, eg 5 sec 60 sec, if nothing o read than it will be next code executed. 某些API具有最大等待值,例如5秒60秒,如果没有读取,则将执行下一个代码。

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 类似的东西,但有错误处理和一些设计模式

When you call Thread.interrupt() on some thread, what happens is that 'interruption' flag is set for that thread. 当你在某个线程上调用Thread.interrupt()时,会发生的是为该线程设置'interruption'标志。 Some methods do check this flag (by Thread.interrupted() or Thread.isInterrupted() ) and throw InterruptedException , but usually only methods that can block do that. 有些方法检查此标志(通过Thread.interrupted()Thread.isInterrupted() )并抛出InterruptedException ,但通常只有可以阻止的方法执行此操作。 So there is no guarantee that InterruptedException will ever be thrown in interrupted thread. 因此,有没有保证InterruptedException永远不会在中断线程被抛出。 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. 如果你没有调用任何抛出InterruptedException方法,那么捕获该异常是没有意义的,因为它根本不会被抛出。 However you can always check if your thread was interrupted by calling Thread.isInterrupted() . 但是,您始终可以通过调用Thread.isInterrupted()来检查您的线程是否被中断。

Calling interrupt() on a thread doesn't stop it, it just switches on the interrupt flag. 在线程上调用interrupt()不会停止它,它只是打开中断标志。 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. 如果您正在该线程中执行阻塞操作,那么您几乎是SOL,因为您的线程在读取时“阻塞”。 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. 这里的一个解决方案是“显式”公开底层连接对象并在其上调用close() ,强制它抛出某种异常,然后可以在线程代码中处理。 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();

Use a try-catch like so: 像这样使用try-catch:

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 我认为应该做的伎俩,你也可以保留一个布尔变量是否退出,所以他们会检查该变量,如果它是真的,停止

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM