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循环,终止线程"); } } }
这方式与前面说的使用标志位终止线程差不多
评论