线程终止的三种方式

文章目录

    • 0.准备演示Demo (1 和 2共用 Demo)
    • 1.线程终止方式--Stop()
    • 2.线程终止方式--interrupt()
    • 3.线程终止方式--标志位

0.准备演示Demo (1 和 2共用 Demo)

public class StopThread extends Thread {
  private int i = 0, j = 0;

  @Override
  public void run() {
    synchronized (this) {
       // 增加同步锁,确保线程安全
       ++i;
       try {
         // 休眠10秒,模拟耗时操作
         Thread.sleep(10000);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       ++j;
    }
  }

  /** * 打印i和j */
  public void print() {
    System.out.println("i=" + i + " j=" + j);
  }
}

​ 程序编写过程中,我们希望做到的就是所写即所得,上述一个测试线程停止方法的一个类,该类中有模拟了耗时操作,主要通过观察变量 i 和 j 的值,来确定 线程 是否 与我们预期的值相符。

​ 提出预期, 我们通过同步锁的机制,想要得到的效果是,当线程执行过程中,保证 i 与 j 的值是我们的预期结果,这里我们想要得到的效果是 i = 1, j = 1。保证最终数据的准确性

1.线程终止方式–Stop()

​ stop() ,方法是Thread类中提供的线程终止的方法之一,但是由于会存在线程安全的问题,所以被弃用。

public class DemoStop {
  public static void main(String[] args) throws InterruptedException {
    StopThread thread = new StopThread();
    thread.start();
      
    // 休眠1秒,确保i变量自增成功
    Thread.sleep(1000);
    
    // 错误的终止
    thread.stop(); 
    while (thread.isAlive()) {
      // 确保线程已经终止
      // 如果没有完全终止,则代表的的是死循环
    } // 输出结果
    thread.print();
  }
}
	执行main 方法会发现,如下效果

在这里插入图片描述

​ 通过分析执行结果,我们与我们的预期效果不符,这样可以得到一个结论

​ Thread的stop(), 虽然可以停止程序的执行,但是却无法保证数据的准确性,当我们想保证数据的准确性的时候,不能使用stop(),因为该方法,只是单纯的在某一个时间点将正在运行的线程终止掉,这样无法保证数据的准确性。

2.线程终止方式–interrupt()

​ 如果目标线程正在调用 Object class 的 wait(),wait(long) 或 wait(long,int)方法、 join()、 join(long,int) 或sleep(long,int) 方法时被阻塞,那么interrupt会生效,该线程的中断状态将被清除,抛出 InterruptedException异常。

​ 如果目标线程是 I/O 或者NIO 中的Channel 所阻塞,同样 , I / O 操作会被中断或者返回特殊异常值。达到终止线程的目的。

​ 如果以上条件都不满足,则会设置此线程为中断状态

public class DemoInterrupt {
  public static void main(String[] args) throws InterruptedException {
    StopThread thread = new StopThread();
    thread.start();
    // 休眠1秒,确保i变量自增成功
    Thread.sleep(1000);
    // 正确终止
    thread.interrupt(); 
    while (thread.isAlive()) {
      // 确保线程已经终止
    } // 输出结果
    thread.print();
  }
}

​ 执行main方法执行结果如下:

线程终止的三种方式_第1张图片

​ 这里可以发现 i 和 j 的值,与我们预期的值相同,并且抛出了InterruptedException异常,由此我们就可以在 通过代码

捕捉异常,然后进行相应的操作。

​ 例如可以

​ try{

​ thread.interrupt();

​ }catch (InterruptException e){

​ //相应的处理操作

​ }

​ 使用interrupt()的好处就是,所写及所得,即使在run() 执行期间,使用 interrupt() 对其打断,也会等run() 里面的内容全部执行完毕后,在通过异常的方式对调用者进行反馈

3.线程终止方式–标志位

​ 如果在线程中循环执行某段代码,可以使用标志位的形式,来控制线程的执行。如下代码:

/** 通过状态位来判断 */
public class DemoFlag extends Thread {
  public volatile static boolean flag = true;

  public static void main(String[] args) throws InterruptedException {
    new Thread(() -> {
      try {
        while (flag) { // 判断是否运行
          System.out.println("运行中");
          Thread.sleep(1000L);
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }).start();
    // 3秒之后,将状态标志改为False,代表不继续运行
    Thread.sleep(3000L);
    flag = false;
    System.out.println("程序运行结束");
  }
}

​ () -> { } 这种代码的写法是一种叫做 lamda表达式的代码写法。

​ 场景描述:我们想要做的事情是类似于长连接的一个事情,而是否保持连接是受调用者控制的。

​ 分析,这里我们通过 flag 在 Thread 中 进行 是否 保持循环的标志位,当 在main() 中对 flag 进行 赋值改变,从而实现控制线程是否继续执行的。

你可能感兴趣的:(个人原创分享)