概念知识

简述

暂停、恢复和停止操作对应在线程Thread的API就是suspend()、resume()和stop()。但是这些API是过期的,也就是不建议使用的。不建议使用的原因主要有:
以suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。
同样,stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为suspend()、resume()和stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方法。

停止线程

1.stop 这个不建议,因为过期了. stop相当于linux的kill进程,是非常暴力的,我不知道用户是不是还有请求没处理完的,这样我强制关闭,可能会有不可预测的问题出现

2.interrupt 优雅的中断,建议用这个
先去阻止后续的请求进来,同时等待当前正在执行的进程都处理完了再去停止掉线程

3…通过指令的方式, volatile boolean isStop = false;

volatile是线程可见的.

4…Thread.interrupted();

对设置的中断标识的线程进行复位,就是给interrupted 变成false.

与线程中断有关的方法有三个:

public void Thread.interrupt() //中断线程
public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread,interrupted() //判断是否被中断,并清除当前的中断状态

线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()来进行判断当前线程是否被中断,不过Thread.interrupted()会同时将中断标识位改写为false。

isInterrupted()方法是boolean类型的,如果这个线程被中断了就返回true,否则就返回false

如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait等),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常,并且在抛出异常后会立即将线程的中断标示位清除,即重新设置为false。

不建议自定义一个取消标志位来中止线程的运行。因为run方法里有阻塞调用时会无法很快检测到取消标志,线程必须从阻塞调用返回后,才会检查这个取消标志。这种情况下,使用中断会更好,因为,

一、一般的阻塞方法,如sleep等本身就支持中断的检查,
二、检查中断位的状态和检查取消标志位没什么区别,用中断位的状态还可以避免声明取消标志位,减少资源的消耗。
注意:处于死锁状态的线程无法被中断

案例interrupt 方式中断线程

中断Thread线程

一秒后中断线程
执行main方法查看控制台打印,和后面的时间戳.你会发现1000毫秒(一秒)后线程中断了

import utils.SleepTools;

public class UseThread extends Thread {
public UseThread(String name) {
super(name);
}

@Override
public void run() {
String threadName = Thread.currentThread().getName();
while (!isInterrupted()) {//检查当前线程是否被中断(平时开发用这个就行了)

System.out.print(threadName + " 正在运行 ,");
System.out.println(threadName + "内部interrrupt标记 = "
+ isInterrupted() + "当前系统时间戳是" + System.currentTimeMillis());

}

//建议在下面的输出语句打断点,更好的查看效果
System.out.print("线程将要停止了, ");
System.out.println(threadName + " interrrupt标记 =" + isInterrupted()+ " 当前系统时间戳是" + System.currentTimeMillis() );//变成true就是中断了
}

public static void main(String[] args) {
UseThread thread = new UseThread("线程1");
thread.start();
SleepTools.second(1);//睡眠一秒
thread.interrupt();//中断线程,其实设置线程的标识位true

}
}

中断Runnable线程

一秒后中断线程
执行main方法查看控制台打印,和后面的时间戳.你会发现1000毫秒(一秒)后线程中断了

import utils.SleepTools;

public class UseRunnable implements Runnable {
@Override
public void run() {
// boolean interrupted = Thread.currentThread().isInterrupted(); 主要这么写,中断线程无效
// while (!interrupted) {// 不要这么写,中断线程无效

while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName()
+ "我是实现Runnable的线程,此时的interrupt标记位是 "
+ Thread.currentThread().isInterrupted() + "当前系统时间戳是" + System.currentTimeMillis());
}

System.out.println(Thread.currentThread().getName() + "interrupt 标记 是" +
Thread.currentThread().isInterrupted() + "当前系统时间戳是" + System.currentTimeMillis());
}


public static void main(String[] args) {
UseRunnable useRunnable = new UseRunnable();
Thread thread = new Thread(useRunnable, "Runnable线程");
thread.start();

SleepTools.second(1);//睡眠一秒

// Thread.currentThread().interrupt(); 这样中断线程是无效的,不要这么写

thread.interrupt(); //设置中断线程

}
}

发生异常中断线程

如果想发成异常就中断线程,请在catch代码块儿里面用Thread.currentThread().interrupt();
如果不这样做会发生某些后果,具体后果运行下面代码去查看效果.

import utils.SleepTools;

public class UseRunnable implements Runnable {
@Override
public void run() {
// boolean interrupted = Thread.currentThread().isInterrupted(); 主要这么写,中断线程无效
// while (!interrupted) {// 不要这么写,中断线程无效

while (!Thread.currentThread().isInterrupted()) {
try {

System.out.println(Thread.currentThread().getName() + "我是实现Runnable的线程,此时的interrupt标记位是 " + Thread.currentThread().isInterrupted());
int a = 1 / 0;
} catch (Exception e) {
/*需要在catch里面手动中断一下,如果想知道不这样写的后果,
可以注释这个代码试试 , 然后仔细观察控制台打印输出语句.,*/
// Thread.currentThread().interrupt();
e.printStackTrace();
}


}

System.out.println(Thread.currentThread().getName() + "interrupt 标记 是" +
Thread.currentThread().isInterrupted());
}


public static void main(String[] args) {
UseRunnable useRunnable = new UseRunnable();
Thread thread = new Thread(useRunnable, "Runnable线程");
thread.start();

SleepTools.second(1);//睡眠一秒

// Thread.currentThread().interrupt(); 这样中断线程是无效的,不要这么写

thread.interrupt(); //设置中断线程

}
}