6

我正在开发一个多线程应用程序来建立与外部服务器的连接——每个服务器都在不同的线程上——并且在有输入之前将被阻塞。这些中的每一个都扩展了 Thread 类。为了便于解释,我们将这些称为“连接线程”。

所有这些连接线程都存储在并发哈希图中。

然后,我允许 RESTful Web 服务方法调用来取消任何线程。(我使用的是 Grizzly/Jersey,所以每个调用都是一个独立的线程。)

我检索特定的连接线程(从哈希图中)并在其上调用 interrupt() 方法。

那么,问题来了,在连接线程中,我如何捕获 InterruptedException?(当连接线程被外部 RESTful 命令停止时,我想做一些事情。)

4

5 回答 5

10

那么,问题来了,在连接线程中,我如何捕获 InterruptedException?

你不能。因为如果您的线程在读取 I/O 操作时被阻塞,它就不可能interrupted。这是因为interrupt只是设置了一个标志来指示线程已被中断。但是,如果您的线程已被 I/O 阻塞,它将看不到该标志。
正确的方法是关闭底层套接字(线程被阻塞),然后捕获异常并将其传播。
因此,由于您的连接线程extend Thread执行以下操作:

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

这样就可以中断在 I/O 上阻塞的线程。

然后在你的run方法中做:

@Override  
public void run(){  

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

    }  
}    

所以在你的情况下,不要catch尝试InterruptedException. 您不能中断在 I/O 上阻塞的线程。只需检查您的线程是否已被中断,并通过关闭流来促进中断。

于 2012-09-01T19:28:46.760 回答
2

阻塞的问题。

悬停者,试试这个代码,也许它会帮助你:

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

你的读取方法,应该检查套接字是否有可用的buytes,例如,如果没有读取它,否则进入speel模式。当睡眠比可用时唤醒(InterruptedException)在pur套接字读取(无论您读取什么)它将被阻止。某些 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);
        } 
     }
  }
}

类似的东西,但有错误处理和一些设计模式

于 2012-09-01T19:24:29.307 回答
2

当您调用Thread.interrupt()某个线程时,会为该线程设置“中断”标志。有些方法会检查这个标志(通过Thread.interrupted()or Thread.isInterrupted())和 throw InterruptedException,但通常只有可以阻止的方法才能做到这一点。所以不能保证InterruptedException会在被中断的线程中抛出。如果您不调用任何 throws 方法InterruptedException,则捕获该异常是没有意义的,因为它根本不会被抛出。但是,您始终可以通过调用来检查您的线程是否被中断Thread.isInterrupted()

于 2012-09-01T19:28:37.477 回答
1

调用interrupt()线程不会停止它,它只是打开中断标志。代码负责处理所考虑的线程中断状态的变化并采取相应的行动。如果您在该线程中执行阻塞操作,那么您几乎就是 SOL,因为您的线程在读取时“阻塞”了。看看我在这里发布的答案。所以基本上,除非你循环一些东西或定期检查该线程中的一些标志,否则你无法在不关闭套接字或类似的东西的情况下突破。

这里的一种解决方案是“显式”公开底层连接对象并调用close()它,强制它抛出某种异常,然后可以在线程代码中进行处理。就像是:

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();
于 2012-09-01T19:29:53.890 回答
-2

像这样使用 try-catch:

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

我认为这应该可以解决问题,您还可以保留一个布尔变量是否退出,这样他们就会检查该变量,如果是真的,停止

于 2012-09-01T19:24:42.040 回答