Java线程在尝试中断和连接主线程时挂起
因此,我已经为这个问题挣扎了一整天,并且已经参考了一些线程教程和示例,但仍然未能达到我想要的结果 我有一个线程,其唯一任务是轮询LinkedBlockingQueue中的字符串,然后使用PrintWriter通过套接字将字符串传递给客户端。该功能运行良好,但我现在正试图通过允许它在连接中断和重新启动时正常失败来增强它。为了实现这一点,我在线程上调用interrupt,然后调用join,最终目标是重新创建要重新开始的线程对象。不幸的是,线程挂起了join的调用,这一定意味着线程从未真正死过,但我完全不明白为什么会这样。相关代码如下Java线程在尝试中断和连接主线程时挂起,java,multithreading,concurrency,freeze,runnable,Java,Multithreading,Concurrency,Freeze,Runnable,因此,我已经为这个问题挣扎了一整天,并且已经参考了一些线程教程和示例,但仍然未能达到我想要的结果 我有一个线程,其唯一任务是轮询LinkedBlockingQueue中的字符串,然后使用PrintWriter通过套接字将字符串传递给客户端。该功能运行良好,但我现在正试图通过允许它在连接中断和重新启动时正常失败来增强它。为了实现这一点,我在线程上调用interrupt,然后调用join,最终目标是重新创建要重新开始的线程对象。不幸的是,线程挂起了join的调用,这一定意味着线程从未真正死过,但我完
try {
resultSetStreamer.interrupt();
resultSetStreamer.join();
logger.info("Streamer finished.");
} catch (InterruptedException e) {}
实际线程代码
class ResultSetStreamer implements Runnable {
GZIPOutputStream gzos = null;
Socket clientSocket = null;
@Override
public void run() {
try {
logger.debug("Thread started.");
// Blocks and waits for an external connection.
clientSocket = serverSocket.accept();
// Creates a compression stream using best possible compression
// to the external connection.
gzos = new GZIPOutputStream(clientSocket.getOutputStream()) {
{
def.setLevel(compression);
}
};
PrintWriter toClient = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(gzos), bufferSize), false);
while (true) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
if (moreRowsToReceive || !dataBuffer.isEmpty()) {
// Synchronisation point.
String row = dataBuffer.poll(pollTime,
TimeUnit.MILLISECONDS);
if (row != null) {
toClient.println(row);
logger.trace("Current row: " + ++currentCount + ".");
}
} else {
toClient.flush();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
gzos.finish();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
logger.debug("Thread finished.");
}
}
主要要看的地方是while(true)循环,它应该始终循环并检查线程是否被中断,在这种情况下,它会抛出在底部捕获的异常,以允许线程死亡。我不认为PrintWriter应该阻止代码的执行。任何帮助都将不胜感激。JVM不会强制中断以终止线程。您需要确保代码调用的所有阻塞调用都支持中断 例如,如果客户端未接收数据,输出缓冲区将填满,toClient.println()将被阻塞,但此调用不支持中断,因此调用.interrupt()不会终止它
我建议添加更多调试日志,以确定代码块的确切位置。在您正在运行的计算机上,尝试启动jconsole并连接到您正在运行的程序。在“线程”选项卡下,您应该能够单击每个线程并查看它当前正在做什么。这将指示您的可运行对象上的哪个语句尚未完成。我很确定您不应该只是捕获
InterruptedException
并打印堆栈跟踪。本文讨论了处理中断异常的可接受方法。谢谢,我将详细介绍。值得一提的是,我目前没有使用Executor接口。我当前的代码使用的是基本线程/可运行类/接口检查您是否在while循环中。如果在ServerSocket的accept()上阻塞,就会发生这种行为。啊,我不确定。很快浏览了这篇文章,意识到我最初的问题可能会模棱两可,因为执行者也使用Runnable。谢谢你的建议,我不知道工具JConsole。尝试运行它,似乎线程在写入套接字时被阻塞。从线程外部关闭套接字以使其抛出异常并退出的最佳方法是什么?JConsole Stacktrace下面的顶行java.net.SocketOutputStream.socketWrite0(本机方法)
从JConsole堆栈跟踪中可以看出,您对toClient.println()阻塞的认识是正确的。您有没有建议在中断时关闭此插座?扩展线程并覆盖interupt()以包括关闭套接字是否合适?从技术上讲,它应该可以工作。根据套接字文档,close()会导致套接字上阻塞的所有线程抛出SocketException。我想知道这是否是最干净的解决方案,因为您的类需要扩展复杂的线程类。也许最好在ResultSetStreamer中保留一个对执行ResultSetStreamer的线程的引用,并使用如下方法:void terminate(){socket.close();Thread.interrupt()}?多亏了这一点,我让线程死掉了。最后,我以这种方式匿名扩展了这个类:resultSetStreamer=new Thread(new resultSetStreamer(),“streamer”){@Override public void interrupt(){super.interrupt();try{clientSocket.close();}catch(IOException printe){e.stacktrace();};resultSetStreamer.start()代码>发送中断信号,然后关闭阻塞套接字。