scheduledfuture.cancel 不会立即终止_Java终止线程的三种方式

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-31 07:36   67   0

最近在复习多线程,那就给大家讲解一下JAVA线程的终止的方式吧。

48f6d8fbc598f12b17915bd96eb9c234.png

在 Java 中有以下 3 种方法可以终止正在运行的线程:

  1. 使用退出标志,通过更改标志,使线程正常退出,也就是让 run() 方法完成后线程中止。简单的说就是通过修改标志(变量的值)让run方法执行完。

  2. 使用 stop() 方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用。

  3. 使用 interrupt 方法中断线程。

1. 使用标志位终止线程

在 run() 方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,run() 方法会被一直执行;比如在服务端程序中可能会使用 while(true) { ... } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位while(false) { ... }的方式来结束 run() 方法。

public static void main(String[] args) {    ServerTest serverTest = new ServerTest();    serverTest.start();    try {      Thread.sleep(10);      serverTest.setFlag(false);    } catch (InterruptedException e) {      // TODO Auto-generated catch block      e.printStackTrace();    }      }}class ServerTest extends Thread{  //保证其他线程获取时都是最新值  public volatile boolean flag=true;      public boolean isFlag() {    return flag;  }  public void setFlag(boolean flag) {    this.flag = flag;  }  //重写run方法  @Override  public void run() {    System.out.println("开始");    while(flag) {      System.out.println("xxxx");    }    System.out.println("结束");  }    }

结果

开始xxxxxxxx......结束

2、使用stop()方法强行结束

我们通过查看 API,我们会看到 java.lang.Thread 类型提供了一系列的方法如 start()、stop()、resume()、suspend()、destory()等方法来管理线程。但是除了 start() 之外,其它几个方法都被声名为已过时(deprecated)。

a11b170e662d756118ab6fc4734eb74a.png

虽然 stop() 方法确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且该方法已被弃用,最好不要使用它。

JDK 文档中还引入用一篇文章来解释了弃用这些方法的原因:《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》

为什么弃用stop:

  1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。

  2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

3. 使用 interrupt() 中断线程

现在我们知道了使用 stop() 方式停止线程是非常不安全的方式,那么我们应该使用什么方法来停止线程呢?答案就是使用 interrupt() 方法来中断线程。

需要明确的一点的是:interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。

也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。这一点很重要,如果中断后,线程立即无条件退出,那么我们又会遇到 stop() 方法的老问题。

事实上,如果一个线程不能被 interrupt,那么 stop 方法也不会起作用。

我们来看一个使用 interrupt() 的例子:

f6d3496116a4c8211ba9975fea6bab52.png

e9eb687ef2f8b3937543e7ed611f9a57.png

从输出的结果我们会发现 interrupt 方法并没有停止线程 t 中的处理逻辑,也就是说即使 t 线程被设置为了中断状态,但是这个中断并不会起作用,那么该如何停止线程呢?

这就需要使用到另外两个与线程中断有关的方法了:

public boolean Thread.isInterrupted() //判断是否被中断

public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态

dd84088264ab6a8e758cecd478f0b3c5.png

b02f63c6c83235be57feab12f31af61b.png

在上面这段代码中,我们增加了 Thread.isInterrupted() 来判断当前线程是否被中断了,如果是,则退出 for 循环,结束线程。

这种方式看起来与之前介绍的“使用标志位终止线程”非常类似,但是在遇到 sleep() 或者 wait() 这样的操作,我们只能通过中断来处理了。

public static native void sleep(long millis) throws InterruptedException

Thread.sleep() 方法会抛出一个 InterruptedException 异常,当线程被 sleep() 休眠时,如果被中断,这会就抛出这个异常。

(注意:Thread.sleep() 方法由于中断而抛出的异常,是会清除中断标记的。)

public class test02 {     public static void main(String[] args) {          F f  =  new F();          f.start();          f.interrupt();          try {              Thread.sleep(100);          } catch (InterruptedException e) {              // TODO Auto-generated catch block              e.printStackTrace();          }          System.out.println("main结束");     }}class F extends Thread{     @Override     public void run() {          try {              System.out.println("开始");              sleep(100000);              System.out.println("结束");          } catch (InterruptedException e) {              System.out.println("xxxxxxxxxxxxxxxx");          }     }     }
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP