如何正确java 强制停止线程java中的线程

java里面如何停止一个运行的线程?
[问题点数:20分,结帖人YHL27]
java里面如何停止一个运行的线程?
[问题点数:20分,结帖人YHL27]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2009年6月 Java大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。java中如何手动停止一个已经start的线程
[问题点数:20分,结帖人huaguoming]
java中如何手动停止一个已经start的线程
[问题点数:20分,结帖人huaguoming]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。5727人阅读
为什么不能使用Thread.stop()方法?
从SUN的官方文档可以得知,调用Thread.stop()方法是不安全的,这是因为当调用Thread.stop()方法时,会发生下面两件事:
1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。
2. 释放该线程所持有的所有的锁
当线程抛出ThreadDeath异常时,会导致该线程的run()方法突然返回来达到停止该线程的目的。ThreadDetath异常可以在该线程run()方法的任意一个执行点抛出。但是,线程的stop()方法一经调用线程的run()方法就会即刻返回吗?
Java代码 &
public&static&void&main(String[]&args)&{ &&&&&&&&&&try&{ &&&&&&&&&&&&&&Thread&t&=&new&Thread()&{ &&&&&&&&&&&&&&&&&&public&synchronized&void&run()&{ &&&&&&&&&&&&&&&&&&&&&&try&{ &&&&&&&&&&&&&&&&&&&&&&&&&&long&start=System.currentTimeMillis(); &&&&&&&&&&&&&&&&&&&&&&&&&&for&(int&i&=&0;&i&&&<span style="color:#c0;&i&#43;&#43;)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&runing..&&&#43;&i); &&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println((System.currentTimeMillis()-start)/<span style="color:#c0); &&&&&&&&&&&&&&&&&&&&&&}&catch&(Throwable&ex)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&Caught&in&run:&&&&#43;&ex); &&&&&&&&&&&&&&&&&&&&&&&&&&ex.printStackTrace(); &&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&}; &&&&&&&&&&&&&&t.start(); &&&&&&&&&&&&&&&&&&&&&&&&&&&&Thread.sleep(<span style="color:#c0); &&&&&&&&&&&&&&t.stop();&&&&&&&&&&&}&catch&(Throwable&t)&{ &&&&&&&&&&&&&&System.out.println(&Caught&in&main:&&&&#43;&t); &&&&&&&&&&&&&&t.printStackTrace(); &&&&&&&&&&} &&&&&&&&}&&
public static void main(String[] args) {
Thread t = new Thread() {
public synchronized void run() {
long start=System.currentTimeMillis();
for (int i = 0; i & 100000; i++)
System.out.println(&runing..& + i);
System.out.println((System.currentTimeMillis()-start)/1000);
} catch (Throwable ex) {
System.out.println(&Caught in run: & + ex);
ex.printStackTrace();
t.start();
// Give t time to get going...
Thread.sleep(100);
t.stop(); // EXPECT COMPILER WARNING
} catch (Throwable t) {
System.out.println(&Caught in main: & + t);
t.printStackTrace();
假设我们有如上一个工作线程,它的工作是数数,从1到1000000,我们的目标是在它进行数数的过程中,停止该线程的运作。如果我们按照上面的方式来调用thread.stop()方法,原则上是可以实现我们的目标的,根据SUN官方文档的解释,加上在上面的程序中,主线程只休眠了100ms,而工作线程从1数到1000000所花时间大概是4-5s,那么该工作线程应该只从1数到某个&#20540;(小于1000000),然后线程停止。&
但是根据运行结果来看,并非如此。
runing..99998
runing..99999
runing..99998
runing..99999
每次运行的结果都表明,工作线程并没有停止,而是每次都成功的数完数,然后正常中止,而不是由stop()方法进行终止的。这个是为什么呢?根据SUN的文档,原则上只要一调用thread.stop()方法,那么线程就会立即停止,并抛出ThreadDeath error,查看了Thread的源代码后才发现,原先Thread.stop0()方法是同步的,而我们工作线程的run()方法也是同步,那么这样会导致主线程和工作线程共同争用同一个锁(工作线程对象本身),由于工作线程在启动后就先获得了锁,所以无论如何,当主线程在调用t.stop()时,它必须要等到工作线程的run()方法执行结束后才能进行,结果导致了上述奇怪的现象。
把上述工作线程的run()方法的同步去掉,再进行执行,结果就如上述第一点描述的那样了
可能的结果:
runing..4149
runing..4150
runing..4151
runing..4152runing..4152Caught in run: java.lang.ThreadDeath
runing..5245
runing..5246
runing..5247
runing..5248runing..5248Caught in run: java.lang.ThreadDeath
接下来是看看当调用thread.stop()时,被停止的线程会不会释放其所持有的锁,看如下代码:
Java代码 &
public&static&void&main(String[]&args)&{ &&&&&&&&&&final&Object&lock&=&new&Object(); &&&&&&&&&&try&{ &&&&&&&&&&&&&&Thread&t0&=&new&Thread()&{ &&&&&&&&&&&&&&&&&&public&void&run()&{ &&&&&&&&&&&&&&&&&&&&&&try&{ &&&&&&&&&&&&&&&&&&&&&&&&&&synchronized&(lock)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&thread-&&&&#43;&getName() &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#43;&&&acquire&lock.&); &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&sleep(<span style="color:#c0);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&thread-&&&&#43;&getName() &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#43;&&&release&lock.&); &&&&&&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&&&&&}&catch&(Throwable&ex)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&Caught&in&run:&&&&#43;&ex); &&&&&&&&&&&&&&&&&&&&&&&&&&ex.printStackTrace(); &&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&}; &&&&&&&&&&&&&&&&Thread&t1&=&new&Thread()&{ &&&&&&&&&&&&&&&&&&public&void&run()&{ &&&&&&&&&&&&&&&&&&&&&&synchronized&(lock)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&thread-&&&&#43;&getName() &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#43;&&&acquire&lock.&); &&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&}; &&&&&&&&&&&&&&&&t0.start(); &&&&&&&&&&&&&&&&&&&&&&&&&&&&Thread.sleep(<span style="color:#c0); &&&&&&&&&&&&&&&&&&&&&&&&&&&&t1.start(); &&&&&&&&&&}&catch&(Throwable&t)&{ &&&&&&&&&&&&&&System.out.println(&Caught&in&main:&&&&#43;&t); &&&&&&&&&&&&&&t.printStackTrace(); &&&&&&&&&&} &&&&&&&&}&&
public static void main(String[] args) {
final Object lock = new Object();
Thread t0 = new Thread() {
public void run() {
synchronized (lock) {
System.out.println(&thread-&& + getName()
+ & acquire lock.&);
sleep(3000);// sleep for 3s
System.out.println(&thread-&& + getName()
+ & release lock.&);
} catch (Throwable ex) {
System.out.println(&Caught in run: & + ex);
ex.printStackTrace();
Thread t1 = new Thread() {
public void run() {
synchronized (lock) {
System.out.println(&thread-&& + getName()
+ & acquire lock.&);
t0.start();
// Give t time to get going...
Thread.sleep(100);
//t0.stop();
t1.start();
} catch (Throwable t) {
System.out.println(&Caught in main: & + t);
t.printStackTrace();
当没有进行t0.stop()方法的调用时, 可以发现,两个线程争用锁的顺序是固定的。
thread-&Thread-0 acquire lock.
thread-&Thread-0 release lock.
thread-&Thread-1 acquire lock.
但调用了t0.stop()方法后,(去掉上面的注释//t0.stop();),可以发现,t0线程抛出了ThreadDeath error并且t0线程释放了它所占有的锁。
thread-&Thread-0 acquire lock.
thread-&Thread-1 acquire lock.
Caught in run: java.lang.ThreadDeath
java.lang.ThreadDeath
&at java.lang.Thread.stop(Thread.java:715)
&at com.yezi.test.timeout.ThreadStopTest.main(ThreadStopTest.java:40)
从上面的程序验证结果来看,thread.stop()确实是不安全的。它的不安全主要是针对于第二点:释放该线程所持有的所有的锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放,那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。
如何正确停止线程
关于如何正确停止线程,给出了一个很好的答案, 总结起来就下面3点(在停止线程时):
1. 使用violate boolean变量来标识线程是否停止
2. 停止线程时,需要调用停止线程的interrupt()方法,因为线程有可能在wait()或sleep(), 提高停止线程的即时性
3. 对于blocking IO的处理,尽量使用InterruptibleChannel来代替blocking IO
核心如下:
If you are writing your own small thread then you should follow the following example code.
private volatile Thread myT
public void stopMyThread() {
Thread tmpThread = myT
myThread =
if (tmpThread != null) {
tmpThread.interrupt();
public void run() {
if (myThread == null) {
// stopped before started.
// all the run() method's code goes here
// do some work
Thread.yield(); // let another thread have some time perhaps to stop this one.
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException(&Stopped by ifInterruptedStop()&);
// do some more work
} catch (Throwable t) {
// log/handle all errors here
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:899276次
积分:11584
积分:11584
排名:第525名
原创:337篇
转载:61篇
评论:207条
难度:高级
类型:实战教学
文章:18篇
阅读:17621
阅读:2355
(1)(1)(6)(4)(5)(4)(9)(10)(15)(3)(3)(4)(7)(11)(19)(5)(3)(3)(25)(15)(21)(4)(5)(11)(1)(8)(3)(3)(4)(7)(7)(1)(5)(6)(11)(7)(7)(4)(1)(3)(2)(2)(2)(2)(2)(1)(4)(14)(2)(20)(10)(13)(4)(7)(8)(8)(41)(1)(10)查看:3829|回复:6
Java codepublic
class Machine extends Thread{& & private
static StringBuffer log =
new StringBuffer();& & private
int count =
0 ;& && &&&public
void run(){& && &&&for(int a =
0;& &&&a&20;a++){& && && && &log.append(currentThread().getName()+&:&+a+&
&);& && && && &if(++count%10==0){& && && && && & log.append(&\n&);& && && && &}& && &&&}& & }& && &&&public
void main(String[] args) {& && &&&Thread main = Thread.currentThread();& && &&&System.out.println(main.getName());& && &&&Machine machine1 =
new Machine();& && &&&Machine machine2 =
new Machine();& && &&&machine1.setName(&m1&);& && &&&machine2.setName(&m2&);& && &&&machine1.start();& && &&&machine2.start();& && &&&/* try {& && && && &Thread.sleep(2000);& && && && &} catch (Exception e) {& && && && &e.printStackTrace();& && &&&}& && &&&*/& && && & System.out.println(main.getPriority());//打印主线程优先级
& && && &System.out.println(machine1.getPriority());//打印m1线程优先级
& && && &System.out.println(machine2.getPriority());//打印m2线程优先级
& && && &System.out.println(log);& & }}
以上代码中创建了m1、m2线程,还有本身的线程main,为什么使用了try代码块中的主线程休眠才可以看到m1、m2执行run()方法的结果?而将try block注释掉之后m1、m2的run()似乎没怎么执行。 个人理解似乎是main主线程急于结束,没能给m1、m2线程执行的机会。但按道理应该是m1、m2并发执行,main()也不应该干涉它们的执行啊。 请高手指教?
好问题,值得讨论
线程基础...
线程的运行顺序不可预知...
你自己看你的程序啊..
你开了两个子线程,这两个线程调用start方法后,并不是马上运行的
线程的运行还要依赖于进程分配,实际上,线程启动更复杂,包含了资源分配,内存分配等等,这些动作都需要CPU时间的
而main进程不管你的进程是不是在运行,它自己管自己的运行,很有可能在你log还没有并两个子线程写入的时候已经被打印了,当然什么东西都没有了
助理工程师
如果不对线程进行控制,线程运行顺序是不可预测的。就算做操作也只能进行大概的预测不能精确。
main方法执行完后你的程序就退出了。当然那两个线程就得不到执行机会,你要把它设置成demo的线程。
为什么log没有打印,不知道有没有人解答下?这个我不太清楚。。
因为你启动线程的时候run方法还没完成 所以会先调用 main()中的其他方法
&&System.out.println(main.getName());&&
&&System.out.println(main.getPriority());
&&System.out.println(machine1.getPriority());
&&System.out.println(machine2.getPriority());
&&System.out.println(log);
这些会先执行因为log是空的所以不会打印出东西
&&public void run(){
&&for(int a = 0; a&20;a++){
&&log.append(currentThread().getName()+&:&+a+& &);
&&if(++count%10==0){
&&log.append(&\n&);
&&System.out.println(log);
把打印语句放到run方法中这样就可以看到效果了
初级工程师
其实楼主要的答案很简单:程序在所有的非Daemon线程结束后终止。
楼主之所以没有看到期望的打印结果,是因为main线程终止时,machine1/2还没来得及执行,不过在程序终止前终归是要执行的。(另外,多运行几次,有时能看到预期结果)
我改了下程序:
public class Machine extends Thread
&&// private static StringBuffer log = new StringBuffer();
&&private static int count = 0;
&&public void run()
&&StringBuffer log = new StringBuffer();
&&for (int a = 0; a & 20; a++)
&&log.append(currentThread().getName() + &:& + a + & &);
&&if (++count % 10 == 0)
&&log.append(&\n&);
&&System.out.println(log);
&&public static void main(final String[] args)
&&Thread main = Thread.currentThread();
&&System.out.println(main.getName());
&&Machine machine1 = new Machine();
&&Machine machine2 = new Machine();
&&machine1.setDaemon(false);// 强调一下,默认就是false
&&machine2.setDaemon(false);
&&machine1.setName(&m1&);
&&machine2.setName(&m2&);
&&machine1.start();
&&machine2.start();
&&// Thread.sleep(2000);
&&// catch (Exception e)
&&// e.printStackTrace();
&&System.out.println(main.getPriority());// 打印主线程优先级
&&System.out.println(machine1.getPriority());// 打印m1线程优先级
&&System.out.println(machine2.getPriority());// 打印m2线程优先级
助理工程师
这个问题应该和Daemon没有关系。虚拟机规范规定虚拟机推出的前提是所有非daemon线程退出。这里main,m1,m2都是非daemon线程,所以虚拟机一定会等他们退出的。
如果把这个程序稍微做一点修改,把run()里的log改成 System.out.print,那么可以看到,m1和m2总是会打印的。
&&public void run() {
&&for (int a = 0; a & 20; a++) {
&&System.out.print(currentThread().getName() + &:& + a + & &);
&&//log.append(currentThread().getName() + &:& + a + & &);
&&if (++count % 10 == 0) {
&&System.out.println();
&&// log.append(&\n&);
那么问题出在哪里呢?看样子是log的问题了。
实例log是StringBuffer类型的,那么这个程序作了什么呢?
log是一个StringBuffer类型的一个static变量,在多个线程中间都可以被操作。m1和m2做的事情是append 往log里追加内容,但这些内容直到main线程退出之前最后一行才打印,因为log不是被同步的,所以main退出的时候m1和m2还没来得及往log里写内容,所以这个时候log是空的,实际上确实是打印了,只是内容是空的。m1和m2等main退出后呢,也确实给log追加内容了,但只是没有打印而已。
我是这么理解的:
在没有变更优先级下,你开的线程都是同级的,Java默认非主线程,就是说:此进程下的所有线程结束导致进程结束,反之之。
main线程先运行,m1、m2创建但不运行,只放到“CPU运行时间等待队列”,这应该是你没能想象的,结合优先级考虑,级别高的,先排队;同级别的,随机排,这就是为什么你拿不准哪个先执行,尤其是运行了一段时间后。
有一点要声明,非同步在CPU里是指,只运行一段时间片段的方法体,就是说,你这三个线程,这执行点,那执行点,不一定哦。
所以,资源要分清。

我要回帖

更多关于 java 停止一个线程 的文章

 

随机推荐