Java如何停止线程

xiaoxiao2025-06-06  45

Preface

启动一个线程或任务都是很简单,线程一般在任务结束后便会自行停止。但是有时我们希望能够在线程自行停止前能够停止它们,比如一些取消操作,或者是应用程序需要快速关闭。博主日前就遇到了这样的问题。

但是在《JAVA并发编程实践》一书中指出:

Java没有提供任何机制,来安全地强迫停止手头地工作。

 

一般来讲,对于Runnable来说,需要做的任务都是在run方法里面进行的,停止一个线程也可以认为是从run方法跳出来吧。

线程停止

使用标志位

这种方式的基本思想为:使用一个标志位,通过这个标志位来决定run方法是继续执行还是直接结束。如下:

static class CancelledTaggedRunnnable implements Runnable{ private volatile boolean cancelled = false; @Override public void run() { while(!cancelled){ //没有停止需要做什么操作 } //线程停止后需要干什么 System.out.println("任务结束了"); } public void cancell(){ cancelled = true; } }

定义一个标志位:cancelled,cancelled为true是即run方法结束,反之继续while里面的任务。通过cancell方法来停止任务。

写一个测试类:

@Test public void testCancelledTaggedRunnnable() throws InterruptedException { CancelledTaggedRunnnable taggedRunnnable = new CancelledTaggedRunnnable(); Thread thread = new Thread(taggedRunnnable); thread.start(); System.err.println(thread.isAlive()); Thread.sleep(1000); taggedRunnnable.cancell(); Thread.sleep(1000); System.err.println(thread.isAlive()); Thread.sleep(1000); System.err.println(thread.isAlive()); }

上述代码的操作为:启动该线程,1s秒调用cancell方法,从而来停止该线程。结果如下

 

 

中断策略

但是使用标志位这种方法有个很大的局限性,那就是通过循环来使每次的操作都需要检查一下标志位。

Java还提供了中断协作机制,能够使一个线程要求另外一个线程停止当前工作。其大致的思想为:调用线程Thread的interrupt方法,在线程内部通过捕获InterruptedException异常来决定线程是否继续还是退出。如下:

static class InterruptRunnable implements Runnable{ private BlockingQueue queue = new ArrayBlockingQueue(10); @Override public void run() { int i= 0; for (;;) { try { //线程的操作 i++; queue.put(i); } catch (InterruptedException e) { //捕获到了异常 该怎么做 System.out.println(queue); e.printStackTrace(); return; } } } }

上述代码通过BlockingQueue的put方法来抛出InterruptedException异常。当内部捕获到该异常时,从而决定是否继续还是直接退出了。

写个测试方法:

@Test public void testInterruptRunnable() throws InterruptedException { InterruptRunnable runnable = new InterruptRunnable(); Thread thread = new Thread(runnable); thread.start(); System.err.println(thread.isAlive()); Thread.sleep(1000); thread.interrupt(); Thread.sleep(1000); System.err.println(thread.isAlive()); Thread.sleep(1000); System.err.println(thread.isAlive()); }

该测试方法大致同使用标志位的测试方法,同样启动该线程后,1秒后调用线程的interrupt方法,从而触发Runnable的内部queue.put(i)操作抛出InterruptedException异常。   测试结果如下:

强行停止(不推荐)

对于多线程,使用中断策略 较为优雅,也是官方的推荐。线程停止前你应该做一些操作,从而保证该线程运行后的数据不会被丢失,这一点在多线程中极为重要。

但是对于中断策略还是有一个很大的缺陷,那就是,必须通过中断的阻塞函数,如:我使用的BlockingQueue的put方法,也可以是Thread.sleep()方法,才能抛出InterruptedException。如果抛不出这样的异常呢?

对于单线程,还有一个简单粗暴的方式,那就是Java已经不再使用的Thread  stop方法。

使用方法即直接调用:thread.stop()即可。

如果你对该线程的操作不再关心了,对结果也不再在意了,使用该方法也是可以的。

但多线程情况下,或者线程带锁的情况下 那就要慎用了。该方法不安全

使用future任务

 

Java还提供一个可带返回值的线程操作,FutureTask。在这个类中可以调用其cancel方法来取消这个任务。

你可以设置true或者false来决定是否让线程出现中断的操作。从而可以使这个中断后能够捕获InterruptedException来决定是否让操作结束。

一般来说,这个类都是跟带返回值的Callable接口一起使用,Runnable接口也是可以使用的,定义线程的操作:

static class MyRunnable implements Runnable{ @Override public void run(){ for(;;){ try { Thread.sleep(300); } catch (InterruptedException e) { System.out.println("线程被中断"); return; } System.out.println("程序运行中...."); } } }

上述代码较简单,不需要多说了。使用FutureTask进行测试,先不让产生中断:

@Test public void test01() throws Exception { FutureTask task = new FutureTask<>(new MyRunnable(), 0); ExecutorService pool = Executors.newFixedThreadPool(1); pool.submit(task); Thread.sleep(1000); System.out.println("任务是否完成?"+task.isDone()); System.out.println("任务是否被取消?"+task.isCancelled()); Thread.sleep(1000); //在这里取消操作 System.out.println(task.cancel(true)); Thread.sleep(1000); System.out.println("任务是否完成?"+task.isDone()); System.out.println("任务是否被取消?"+task.isCancelled()); Thread.sleep(5000); }

通过线程池的方式来提交任务,让其运行,2秒后取消任务,查看控制台:

但是FutureTask的cancelle方法并不能真正的停止当前线程,其主要思想还是如同中断策略。也就是说,如果我们不设置task.cancell(true),那么任务还不会被中断,如,我们改为task.cancell(false),结果如下:

虽然此时调用了task.cancell(false)方法,但是通过isDone,isCancelled方法并不能说名任务就结束了。如上,任务还在继续。

 

综上,Java并没有停止线程的方法,如果需要手动的停止,还是建议较优雅的中断策略,或者FutureTask。 

 

转载请注明原文地址: https://www.6miu.com/read-5031346.html

最新回复(0)