我正在开发一个通过网络读取和处理数据的应用程序。在测试程序的连接/断开逻辑时,我注意到我的消费者线程在达到关闭状态时没有关闭。以下是消费者类的剥离版本。
import java.io.InputStream;
public class Consumer implements Runnable
{
private final InputStream input;
public Consumer(InputStream input)
{
this.input = input;
}
@Override
public void run()
{
byte readBuffer[];
readBuffer = new byte[1];
int goodData;
try
{
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
Thread.currentThread().interrupt();
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}
}
catch(Exception e)
{
System.out.println("closing "+Thread.currentThread().getName() +" because of an exception "+e.getClass());
return;
}
System.out.println("closing "+Thread.currentThread().getName());
}
}
我创建了一个虚拟主类来演示这个问题。
public class ExampleOfInterruptNotWorking
{
public static void main(String[] args)
{
byte[] bytesToWrite = new byte[]{0, 1, 2,3,4,5,6,65,23,65,21,54,13,54,1,76};
Consumer C;
Thread ConsumerThread;
PipedInputStream PIS = null;
PipedOutputStream POS = null;
try
{
PIS = new PipedInputStream();
POS = new PipedOutputStream(PIS);
C = new Consumer(PIS);
ConsumerThread = new Thread(C);
ConsumerThread.start();
POS.write(bytesToWrite);
POS.write(bytesToWrite);
bytesToWrite[1] = 27;
POS.write(bytesToWrite);
ConsumerThread.join();
}
catch(Exception e)
{
System.err.println("Unexpected exception in main");
e.printStackTrace(System.err);
}
finally
{
try
{
PIS.close();
POS.close();
}
catch(Exception ex)
{
//shouldn't happen in example
}
System.out.println("exiting main");
}
}
}
当您按照写入的方式运行此代码时,使用者会检测到中断,但在管道为空(不是我想要的)之前不会停止执行。只是为了尝试,我改为Thread.stop()调用,它做了我想要的,但我不想把它留在生产代码中。我意识到我可以使用一个简单的return语句,但这不是线程可以退出的唯一点,我希望有一些通用的退出代码来清理资源。所以,我的问题是,为什么消费者线程不被中断?我有一个很好的方法可以拥有共同的退出代码吗?
谢谢!
答案 0 :(得分:9)
当线程处于休眠状态,等待连接等(基本上任何可中断的阻塞调用)和interrupt()被调用时,抛出InterruptedExceptions。
如果线程正在运行,那么线程中断标志将被设置但不会抛出异常,你应该用myThread.isInterrupted()
检查标志。
您可以在此处找到更多信息: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
答案 1 :(得分:2)
您希望抛出InterruptedException
哪种方法? Thread.interrupt()
并没有抛弃它,也不是你的任何方法。那么你期望这个检查异常应该来自哪里?
您的代码无效,因为interrupt()
几乎没有在线程上设置interrupted
标志。您必须使用Thread.isInterrupted()
明确检查该标志。仅当有问题的线程在当时正在休眠或阻塞时才会抛出InterruptedException
。因此,如果您中断不同的线程并且该线程正在休眠,sleep()
将抛出InterruptedException
。
现在详细解决您的问题。 例外情况适用于特殊情况。你的线程完成处理的事实并非例外情况,这是你绝对期望的。出于同样的原因,读取文件超过结束不会引发异常 - 文件结束是您应该期待的 - 所有文件都已结束。此外,您不应该使用异常来控制程序流。
在你的情况下,使用return
语句(当run()
返回时,线程死掉)或以其他方式中断循环。您发布了太多代码进行分析。
答案 2 :(得分:0)
你可以简单地使用break来标记
OUTER:
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
//Thread.currentThread().interrupt();
break OUTER;
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}