Java 终止(销毁)线程的方法(含完整示例)
结束线程有以下三种方法:
(1)设置退出标志,通过外围改变标志位状态,使线程正常退出,也就是当run()方法完成后线程终止
(2)使用interrupt()方法中断线程
(3)使用stop方法强行终止线程(不推荐使用Thread.stop,此方法已经被废弃,使用它是不安全的,不在本文讨论范围以免更加混淆知识点)
----------------------------------------------------------------------------------------------------------------------
首先要清楚java线程是一次性消费品,就是你任务执行完,线程也会自动终止并退出线程,并不需要我们主动去终止它。而我们所说的终止线程一般都指线程还未处理完任务,任务正在执行中,此时你决定放弃任务的继续执行,手动去终止线程的执行,如Runable的run方法中有一个while循环,或是run方法中有一个间隔定时循环任务,或是for循环等,此类线程循环在未满足停止条件前,它不会自动终止任务,此时如你放弃任务,则需要人为的去终止。下面简单说一下终止线程的两个有效方式,如有好的其它方法,大家可以留言分享!!!博主在此谢谢!
1 标志位退出方式:在线程体设置标志位,此标志位可以线程外改变状态,每次循环都为判断此标志位是满足条件,否则终止任务,示例代码下如:
public class ShoujiOdmThread extends Thread {
//volatile修饰符用来保证其它线程读取的总是该变量的最新的值,
public volatile boolean exit = false;
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
while(!exit) {
try {
Thread.sleep(1000);
//此处模拟耗时任务,休眠1秒
System.out.println("shoujiodm.com");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("线程结束了");
}
}
// 需要终止线程处的使用
ShoujiOdmThread thread = new ShoujiOdmThread();
thread.exit = true;示例二,线程池线程的终止
static CountDownLatch countDownLatch ;
public static void main(String[] args) {
// TODO Auto-generated method stub
countDownLatch = new CountDownLatch(1);
try {
Thread.sleep(100000);
countDownLatch.countDown(); //此处主动终止定时循环任务
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start() {
ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();
final String jobname = "work";
final Map<String,Future> futures = new Map<>();
Future futureTask = schedule.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//do your task here
if(countDownLatch.getCount() == 0) {
Future future = futures.get(jobname);
if(null != future) {
future.cancel(true);
}
}
}
},30,30,TimeUnit.SECONDS);
futures.put(jobname,futureTask);
try {
countDownLatch.await();
schedule.shutdown();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
2 使用interrupt方法终止线程
我们先来看看含有interrupte的几个方法
public boolean Thread.isInterrupted() //判断是否被中断 (实例方法)
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态 (静态方法)
两个方法的源码:
public boolean isInterrupted() {
return interrupted; //返回中断状态值
}
public static boolean interrupted() {
Thread t = currentThread();
boolean interrupted = t.interrupted;
// We may have been interrupted the moment after we read the field,
// so only clear the field if we saw that it was set and will return
// true; otherwise we could lose an interrupt.
if (interrupted) {//如果当前线程已是中断状态
t.interrupted = false; //将线程的中断状态改为false;
clearInterruptEvent();
}
return interrupted; //返回中断状态值
}其他线程调用当前线程的interrupt方法时,即是线程设置一个标识,表示当前线程可以中断了,至于什么时候中断,取决于当前线程。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程,而是通知目标线程,有人想要你终止。
使用interrupt方法终止线程方式分两种情况:
(1)当前线程处为阻塞状态,
线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,sleep,join,wait方法是会抛出InterruptedException异常,我们在使用此三方法时也是需要去捕获InterruptedException异常的,
如下是Thread的sleep,join方法实现源码截图


如下Object类中的wait方法实现源码截图

如果当前线程处于阻塞状态下,我们执行线程的interrupt方法,则线程会接收到一个中断异常(InterruptedException),从而终结被阻塞状态,我们可以在捕获中断异常后去终止该线程,

(2)线程未处于阻塞状态
使用上面interrupte 方式终止线程,只作用于那些因为执行了sleep、wait、join方法而阻塞的线程,使他们不再阻塞并同时会抛出InterruptedException异常,
如果线程没有被阻塞,这时调用 interrupt()是不起作用,所以这方式需要用户自己去监视线程的状态为并做处理,似乎在实际的工作中很少遇到此种情况,据自己个人经验我们开启多线程都是一般为处理耗时任务,不会轻易去让线程进入阻塞状态,或是线程进入阻塞状态的时间尽量短,
示例代码如下:
public class StopThread {
public static void main(String[] args) {
// TODO Auto-generated method stub
ODMThread thread = new ODMThread();
thread.start();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread.interrupt();//调用interrupt 设置线程中断标识位
}
private static class ODMThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
//while循环方式 //判断是否被中断
while(!isInterrupted()) {
//只有当前线程可终止标识符为false时,才可进入while循环内执行业务
//而线程的终止标识符是可以在线程体外改变的
System.out.println("此处模拟耗时业务.......");
}
//for循环方式 //判断是否被中断
// for(int index =0;index <=1000;index++) {
// System.out.println("此处模拟耗时业务.......");
// if(Thread.currentThread().isInterrupted()) {
// //当前线程可终止标识被设置为true,则终止for循环
// break;
// }
// }
System.out.println("跳出while循环,终止线程");
}
}
}这方式与前面说的使用标志位终止线程差不多






评论