虽说Thread类提供了stop()和suspend()方法,但这两种方法过于粗暴,如果线程占用了一些资源(如打开了一个文件,建立了一个数据库连接什么的),直接stop()或是suspend()是会产生问题的。
要终止Thread,最好的方法就是让run()方法正常运行完毕,不过有的run()方法里面直接是一个while (true),这时就要使用一些特殊的手段。
1. 使用中断
基本思想就是在run()方法中的while (true)里检查线程是否中断,如果中断就退出(当然,退出之前可以做一些关闭资源的操作);这么一来在主线程中就可以调用Thread.interrupt()来中断线程,进而使线程退出。
public class Runner3 implements Runnable {
@Override
public void run() {
while(true) {
System.out.println(new Date());
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
// 不使用Thread.sleep(1000)
// 使用while来消耗一秒钟时间
}
if (Thread.currentThread().isInterrupted()) { // 时刻检查该线程是否中断
// 或者使用 if (Thread.interrupted()) {
return; // 如果线程中断就退出
}
}
}
}
public class MultiThreadTest3 {
public static void main(String[] args) {
Runner3 r = new Runner3();
Thread t = new Thread(r);
t.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// do nothing
}
t.interrupt(); // 中断Thread t,使run()方法退出,线程结束
}
}
如果在run()方法中的while (true)里有可能导致InterruptedException的操作,那么退出run()方法的代码可以放在catch语句里。
public class Runner2 implements Runnable {
@Override
public void run() {
while(true) {
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return; // 发生中断异常时,线程直接退出
}
}
}
}
public class MultiThreadTest2 {
public static void main(String[] args) {
Runner2 r = new Runner2();
Thread t = new Thread(r);
t.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// do nothing
}
t.interrupt(); // 中断Thread t,使t.sleep()时产生中断异常,进而终止线程
}
}
2. 使用标志位
使用标志位boolean flag,将run()方法中的while (true)改为while (flag)(轮询标志位),主线程中就就可以通过修改flag来退出线程。
public class Runner4 implements Runnable {
private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
while(flag) {
System.out.println(new Date());
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
// 不使用Thread.sleep(1000)
// 使用while来消耗一秒钟时间
}
}
}
}
public class MultiThreadTest4 {
public static void main(String[] args) {
Runner4 r = new Runner4();
Thread t = new Thread(r);
t.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// do nothing
}
r.setFlag(false); // 设置标志位,使run()方法退出,线程结束
}
}
这个方法有一个缺点:如果while (flag) {...}方法阻塞了,则flag的设置会失效。
3. 最好的方法是使用线程池
当线程不用了,就让它sleep并放进队列中,这样可以最大限度地利用资源。不过这暂时不在本文的讨论范围内。
2010-10-04 补充:
注意这里说的退出是这样的一种情况:主线程(比如说 main 方法)创建了一个 Thread t,然后想在主线程中使t退出。
文章一开始说的 stop()、suspend() 方法的问题是:主线程一句 t.stop() 或是 t.suspend() 就了事了,t 在 run() 方法中没有机会去关闭资源,不像中断或是轮询标志位的方法中,t 在 run() 方法里还握有一点主动权
2011-11-03 补充:
方法2可以使用的一个优化步骤是将标志位设置为 volatile
分享到:
相关推荐
NlsLexicons004b
NlsData004b
作业#004b逻辑运算符(总计14) 目标: 评估布尔逻辑语句 有时您可能需要检查多个条件。 一种选择是将if语句嵌套在if语句中,但是您也可以使用运算符检查条件语句 打开名为example1.py的文件,以查看“和”运算符...
SDSS计算研究Python作业作业#004b逻辑运算符(总计14) 目标: 评估布尔逻辑语句有时您可能需要检查多个条件。 一种选择是将if语句嵌套在if语句中,但是您也可以使用运算符检查条件语句打开名为example1.py的文件,...
SDSS计算研究Python作业作业#004b的循环(总计成绩15) 目标: 新变量类型:元组使用for循环遍历元组的成员使用for循环遍历整数序列可以用来跳过并继续迭代使用break从for循环退出当您要重复一段代码一定次数时,...
SDSS计算研究Python作业作业#004b的循环(总计成绩15) 目标: 新变量类型:元组使用for循环遍历元组的成员使用for循环遍历整数序列可以用来跳过并继续迭代使用break从for循环退出当您要重复一段代码一定次数时,...
作业#004b的循环(总计成绩15) 目标: 新变量类型:元组 使用for循环遍历元组的成员 使用for循环遍历整数序列 可以用来跳过并继续迭代 使用break从for循环中退出 当您要重复一段代码一定次数时,for循环很有用。...
SDSS计算研究Python作业作业#004b的循环(总计成绩15) 目标: 新变量类型:元组使用for循环遍历元组的成员使用for循环遍历整数序列可以用来跳过并继续迭代使用break从for循环退出当您要重复一段代码一定次数时,...
【软件名称】:Your Uninstaller! Pro 7.3.2011.11 【软件语言】:多国语言 【软件分类】:系统工具 【软件格式】:RAR 【档案大小】:6.24 MB ...SHA1: A9CE64A71A7D0F5CC004B3CBA9B9A5AA156E8734 CRC32: 7BFEB478
0013F5DC 004B3DC1 <JMP.&Communicate.#10> asktao.004B3DBC 0013F5F0 00596540 asktao.004B3DB0 asktao.0059653B 0013F638 004815C5 asktao.00596440 asktao.004815C0 0013F64C 004894CC asktao.004815B0 asktao....
DVR USB监控驱动
三晶变频器说明书
并口多功能BIOS编程器最新0.98+版安装程序。 (05版本)支持USB供电 变压器供电 双电源供电最新版本并口编程器,兼容老版本编程器) 增加ST PMC PM39F020 PM 39F040 重新整理芯片型号选择,选择芯片更加方便。 修改...
三晶变频器8000B说明书!里面包含详细操作说明,通讯协议,故障代码,等! 给自己也备一份!!!
更新此代码,解决Delphi7编译出的程序在调用WebService时总是因windows数据执行保护而失败的问题。
置接口跳转 (&DataSend, 到十进制 (“004B3370”), “DataSend”) ' 数据封包 DataSend 置接口跳转 (&GCMoneySend, 到十进制 (“004075EA”), “GCMoneySend”) ' 钱的函数 GCMoneySend 置接口跳转 (&...
十字绣设计软件 cshow发布过破解补丁,但是怎么不好用呢?而且觉得一个小小的软件还用补丁怪累赘的,所以直接用标志位破解了。 004B86E2前的关键call跟进去,然后把al返回1就可以了
WM_CANCELJOURNAL= $004B //当某个用户取消程序日志激活状态,提交此消息给程序 WM_NOTIFY = $004E //当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口 WM_...
9D004B7EA2005187AD004E82A6004D81A300548BB100588FB3006298BB00679E C20074B0DA006BA3C80058768B0037719B00366E970020415A0028516F003971 9A00396F9700396D95003D759F003B729A003D759D003D739B003B6F97003666 ...