用复杂的子例程杀死一个线程。爪哇
Posted
技术标签:
【中文标题】用复杂的子例程杀死一个线程。爪哇【英文标题】:Killing a thread with a complex subroutine. Java 【发布时间】:2012-02-06 04:44:16 【问题描述】:与其他许多人一样,我在不使用 stop() 的情况下杀死我的线程时遇到了问题。 我曾尝试在我的线程 run() 例程中对带有 while 循环的变量使用 volatile。
据我所知,问题在于,while 循环只在每轮之前检查变量。我运行的复杂例程需要很长时间,因此线程不会立即终止。
我要终止的线程是一个连接到另一台服务器的例程,它使用了很长的时间。我想为此设置一个中止按钮。 (终止线程)。我会尝试用一些代码来解释。
class MyConnectClass
Thread conThread;
volitile boolean threadTerminator = false;
..some code with connect and abort button..
public void actionPerformed(ActionEvent e)
String btnName = e.getActionCommand();
if(btnName.equalsIgnoreCase("terminate"))
threadTerminator = true;
conThread.interrupt();
System.out.println("#INFO# USER ABORTED CURRENT OPERATION!");
else if(btnName.equalsIgnoreCase("connectToServer"))
conThread = new Thread()
public void run()
while(threadTerminator == false)
doComplexConnect(); //Uses a loooong time
conThread.start();
如何立即终止我的“连接”线程? 谢谢。
【问题讨论】:
你能用普通的中断设施中断线程吗? 我正在尝试使用 conThread.interrupt();希望线程会中止可能的子线程。我的连接方法使用 ssh 连接到另一个位置,它等待远程位置响应。是“conThread.interrupt();”吗?你有正常的中断设施吗? 你能澄清你的外部问题吗,因为很可能解决方案与线程无关。为什么需要这么快中止操作? 我的 conThread 正在等待远程 ssh shell 应答。这就是需要这么长时间的原因。我想用我的“中止”按钮中止这个线程(和等待)。我的主线程在等待这个完成时禁用了其他连接按钮。我想中止,以便我可以启用其他操作的按钮。 所以关闭 TCP 连接,等待将停止。 (停止你想要停止的实际事情,而不是线程。) 【参考方案1】:Java 不久前放弃了 Threads 中的 stop() 方法,因为不优雅地杀死 Thread 会在 JVM 中引起巨大的问题。来自 stop() 的 Javadoc:
使用 Thread.stop 停止线程会导致它解锁所有已锁定的监视器(这是未检查的 ThreadDeath 异常沿堆栈传播的自然结果)。如果以前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。停止的许多用法应该由简单地修改一些变量以指示目标线程应该停止运行的代码替换。目标线程应该定期检查这个变量,如果变量指示它要停止运行,则以有序的方式从它的 run 方法中返回。如果目标线程等待很长时间(例如在条件变量上),则应使用中断方法来中断等待。
在大多数情况下,只要您可以安全地终止,您就可以检查 threadTerminator var,并优雅地处理线程退出。见http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
【讨论】:
嗨,谢谢。问题是我无法检查 threadTerminator,因为我的 conThread 正在等待远程 ssh shell 应答。这就是需要这么长时间的原因。我想用我的“中止”按钮中止这个线程(和等待)。?【参考方案2】:如果您正在执行长 I/O,您可能会遇到麻烦。某些 I/O 操作会引发 InterruptedException,在这种情况下,您可以中断线程,并且,如果您在该 I/O 中,该异常将被抛出更多或更少立即,您可以中止和清理线程。出于这个原因,中断线程比使用特殊的自定义 threadTerminator 变量更可取——它更加标准。在 I/O 之外的主代码中,定期检查 interrupted() 或 isInterrupted()(而不是 threadTerminator == false)。
如果您正在执行不抛出 InterruptedException 的 I/O,有时您可以关闭 Socket 或类似的,并捕获 IOException。有时你会被卡住。
【讨论】:
您好,感谢您的支持。我还在做这个。我会尝试检查interrupted()。【参考方案3】:你为什么不中断线程并继续前进,让它挂起直到它完成?用户可以在旧线程优雅完成时启动不同的操作(线程)(从我看来,你已经在做很多事情了)
当用户开始大量点击“connectToServer”(很多线程)或线程无法终止(挂起的线程)时,您会遇到麻烦。但也许它足以满足您的目的?
编辑: 实现一种机制来防止产生新的线程会很简单,除非“很好”(例如,使用信号量)。
棘手的部分将是决定打开一个新连接是否好。您可以询问原始线程(即有一个 isalive() 方法)或您尝试连接的一方。或者您可以寻求超时解决方案。例如,您可以让 conthread 更新一个时间戳,并在 1 分钟内未更新时间戳等情况下确定它已失效。最普遍适用的解决方案可能是超时解决方案。
【讨论】:
您好,这是个好建议。唯一的问题是 conThread 正在向我的主线程正在更新(gui)的控制台发送更新。因此,如果我运行 multible conThreads 控制台窗口将是一团糟。比如:连接、连接、发送命令、断开连接、发送命令等。有什么建议吗? :) 这可能很简单:要么确保在任何此类操作之前,线程检查它是否应该生存或死亡(检查更新发送方法中的中断状态)。或者忽略这些更新,除非它们来自唯一应该仍然存在的线程(恕我直言,这很混乱)。以上是关于用复杂的子例程杀死一个线程。爪哇的主要内容,如果未能解决你的问题,请参考以下文章