在下面的代码中,我有一个while(true)循环。考虑到这样一种情况,在try块中有一些代码,线程应该执行一些大约需要一分钟时间的任务,但是由于一些预期的问题,它一直在运行。我们能停下来吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class thread1 implements Runnable {
/**
* @param args
*/
public static void main (String[] args ) {
// TODO Auto-generated method stub
thread1 t1 = new thread1 ();
t1. run();
}
@Override
public void run () {
// TODO Auto-generated method stub
while(true){
try{
Thread. sleep(10);
}
catch(Exception e ){
e. printStackTrace();
}
}
}
} |
- 在windows:task manager中,结束javaw进程。:)
- @这位精英先生很好!
- @这位精英先生,你在说什么?它只适用于Windows用户,这不是一个多平台的方式来做它,因此,它不是非常爪哇:OP
- 没有直接连接到您的问题,但是不要犯错误调用可运行对象run()方法,而不是线程对象start()方法。一个很常见的错误:S。
- @ Oltarus,对于非基于Windows的系统,查找Java运行时进程ID并使用EDCOX1 OR 1,其中EDCOX1×2是Java运行时进程ID。高兴吗?P
- @这位精英先生很高兴!
- @精英绅士,windows命令并不像kill -9那样有名,但它确实存在:taskkill /pid,或者在你的情况下,taskkill /IM javaw.exe。
首先,你不能在这里开始任何线程!您应该创建一个新的线程,并将名称混乱的thread1Runnable传递给它:
1 2 3
| thread1 t1 = new thread1 ();
final Thread thread = new Thread(t1 );
thread. start(); |
现在,当您真正拥有一个线程时,有一个内置的功能可以中断正在运行的线程,称为…interrupt():
但是,单独设置此标志没有任何作用,您必须在运行线程中处理此问题:
1 2 3 4 5 6 7 8 9 10 11
| while(!Thread. currentThread(). isInterrupted()){
try{
Thread. sleep(10);
}
catch(InterruptedException e ){
Thread. currentThread(). interrupt();
break; //optional, since the while loop conditional should detect the interrupted state
}
catch(Exception e ){
e. printStackTrace();
} |
需要注意的两件事:当线程isInterrupted()时,while循环将结束。但是如果线程在睡眠期间被中断,那么jvm会通过将InterruptedException从sleep()中抛出来通知您。抓住它,打破你的循环。就是这样!
其他建议:
Deprecated. This method is inherently unsafe[...]
- 添加你自己的旗帜并密切关注它是很好的(记住使用AtomicBoolean或volatile)!但是,如果JDK已经为您提供了这样的内置标志,为什么还要麻烦呢?额外的好处是中断sleeps,使线程中断更具响应性。
- 很可能您想检查它Thread.interrupted()(方法清除标志)
- +1,但我添加了重新设置中断标志。一般来说,继续使用最佳实践是一个好主意。清除中断标志(如@bestsss所建议的)通常不是一个好主意,因为使用上下文未知。如果OP试图编写一个util或一些lib/客户机代码呢?你不想使用一些恶意隐藏主程序中断请求的API,是吗?
- @蒂姆,代码没有设置标志,所以是Thread.interrupt(),但是……最好的做法是扔东西。虽然离开标志确实有帮助,但最好抛出一些东西,这样代码流就可以快速地从范围外转移,而不是在每个语句中轮询标志。我不同意不断地轮询标志是最好的选择。库代码通常是这样做的,即Thread.interrupted() + throw InterruptedException,您可以在java.util.concurrent.locks中看到它。
- @贝斯特…对,它抛出一个InterruptedException,这样您就不必在返回每个阻塞操作时检查标志。但是,在处理InterruptedException时,API应该做的事情是重新抛出它,或者重新设置中断标志。您可以阅读IBM白皮书iM.COM/DeaveAsWorks/Java/Labaly/J-JTP05266/NETX.HTML或在实践中读取Brian Goetz"Java并发"的详细信息。P.S.Thread上的方法interrupt()不是static。
停止线程的正确方法是对interruptit(stop()已被弃用,可能会产生严重的副作用):
这将导致InterruptedException被Thread.sleep()或Object.wait()等方法抛出。
然后只需为这个异常添加一个catch块,并简单地将break从while循环中去掉。
编辑:我现在意识到你的无限循环是在主线程中运行的,没有由你的代码创建的线程,它只是run()宁一个Runnable。您需要在某个时刻调用Thread.start(),以生成一个新线程。
将捕获中断移动到循环外部。这不需要更多的代码行,它只是正确地处理中断,即操作被中断。
停止任意线程的唯一方法是中断它。保留对它的引用,然后调用中断方法。
在启动线程之前创建一个设置为true的字段boolean keepGoing,并用while (keepGoing)替换while (true)。在某个时刻,您可以决定在哪里,只需将keepGoing的值更改为false,它就会退出循环。
- 不要忘记以线程安全的方式执行此操作!
- 此外,EDCOX1 0是一个Java关键字,不能用它作为标识符…
- @托马什·努尔基维茨修好了,换成了埃多克斯1〔1〕!
- -1,因为这实质上是复制了中断标志的功能,但是以非常非标准的方式,没有提到/考虑线程的可见性。
我建议使用Thread.interrupt()(如@bohemian所述)。与使用特殊标志相比,它有两个优势:
然而,这不是一颗神奇的子弹。如果试图停止的线程正在执行常规代码,则需要定期检查其interrupted()标志,否则它不会停止。这就让我们和船一样,有了一个特别的旗帜机制。线程必须配合,否则无法(安全地)停止。
这是个阴暗的地方。一方面,有一个InterruptedIOException,其javadoc说"表示I/O操作被中断"。另一方面,对于各种java.io流类,javadocs中没有明确提到异常。
确实,某些第三方代码可能无法正确处理interrupted标志,因此中断可能会被"吃掉"。但是如果你有源代码的话,你可以检查一下。这种情况与第三方代码没有太大的不同,第三方代码没有注意您的特别标志机制。
我不建议使用Thread.stop()。基本上是薄片状的。有些人声称这对他们有效,但在我看来,他们要么是在处理一个有效的特殊案件…或者他们很幸运。
- @斯蒂芬,很多代码(称之为第三方)倾向于吃掉这个标志(或者不重置它)。顺便说一句,线程挂起/停止和检查堆栈(爬行)是否有危险的停止位置似乎对我有好处。
- @最好的-我不建议这样做!它需要深入了解您的代码库(知道危险的地方在哪里)并且是脆弱的。(下一个接触代码的人可能不太熟悉它…)
- @斯蒂芬,真正脆弱的代码就是这样的代码之一:lock.lock();try finally(lock.unlock()getting threaddeath in the finally block,totally block,totally block)。java.util.concurrent.locks.中的任何堆栈位置都是非常糟糕的,所以大多数java.net都是可以停止的。我从不推荐任何人自己尝试,因为它(我想)也依赖于JVM等等。很遗憾,Java没有C线程停止语义。
- @bestsss-c Thread.Abort()显然也有同样的问题;参见stackoverflow.com/questions/1327102/…
- @斯蒂芬,但它确实执行了finally块,它不能被捕获和吃掉(即捕获后,它总是被重新抛出)。这不是万能的,但是Java版本使J.U.C.Load读坏了,这是我唯一的抱怨,如果你碰巧落在某个真正的全局锁上,你就完蛋了。当然,我不会为了好玩而通过stop()来阻止theads,但有时没有其他方法(不是我的选择)。我不喜欢重启一个进程,服务器必须运行几个月,直到核心代码需要修复。
- 进程/服务器必须运行数月的要求在我看来像是自我造成的痛苦。
- @斯蒂芬,我不是在说网络服务器。我不能接受泄露。如果没有泄漏,则无需重新启动。假设您有带共享内存的多核MMO游戏服务器,您想重新启动它吗?不完全是我的情况,但没有那么不同。
- @最好的-在质量上没有区别。如果你有一个应用程序需要杀掉线程,那么你有一个设计糟糕的应用程序和/或bug。如果您的应用程序没有故障转移和/或偶尔重新启动的规定,那么您的应用程序设计得很差。对于一个组件的一个/每个实例,需要持续运行时间的系统设计不好。最好的解决方案是修复设计…不要采取"英勇"的措施来避免重启。
- @斯蒂芬,线程"需要杀戮",因为一些意想不到的错误/条件,这不是正常现象,但会发生。能够修复不丢失几千个套接字(以及相关的客户机状态)的bug对我来说是一项壮举。重新部署某些模块不到一秒钟。我举了一个游戏为例,不可能关闭整个服务器而不给玩家带来显著的负面影响,不管是否有服务器来承载负载。我从来没有说过,如果服务器膨胀,客户机将无法恢复,但这并不是为客户机提供适当体验的计划。