1、不正确的线程中止

stop为不正确的线程中止方式,并且清楚监控器锁的信息,但是可能导致线程安全问题,目前jdk不建议使用。
Destroy:JDK未实现该方法。
下面我们使用一段测试代码来验证stop的不正确性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();
}
System.out.println("----模拟耗时结束------");
++j;
}
}
//打印i和j的值
public void print(){
System.out.println("i=" + i + ",j=" + j);
}
}

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) throws InterruptedException {
StopThread stopThread = new StopThread();
stopThread.start();
//休眠1秒,确保变量i自增成功
Thread.sleep(1000);
//中止线程
stopThread.stop();
while (stopThread.isAlive()){
//确保线程已经终止
}
//打印结果
stopThread.print();
}

StopThread 线程运行后,目的是对全局变量i和j的值都自增1,在主线程中对该线程stop后的结果如下:

i=1,j=0

显然stopThread线程被中止后,sleep后面的代码都没有再被执行。导致程序最终结果并不是我们想要的结果,因为理想值应该i=1且j=1。

2、正确的线程中止

2.1、interrupt

中断在java中主要有3个方法,interrupt(),isInterrupted()和interrupted()。

  • interrupt(),在一个线程中调用另一个线程的interrupt()方法,即会向那个线程发出信号——线程中断状态已被设置,只是中断状态被改变(设置为true),该线程并不会被中断或者中止,并不像stop会直接中断线程的执行。
  • isInterrupted(),用来判断当前线程的中断状态(true or false)。
  • interrupted()是个Thread的static方法,用来恢复中断状态,并返回当前中断状态。

如果目标线程在调用Object class的wait()、wait(long)或者wait(long,int)方法、join、join(long,int)或者sleep(long,int)方法时被阻塞,那么Interrupt会生效,该线程的中断将被清楚,抛出InterruptedException异常。
如果目标线程被I/O或者NIO的Channel所阻塞,同样I/O操作会被中断或者返回特殊常值。达到终止线程的目的。
如果以上条件都不满足,则这时调用interrupt方法将不起作用,只是线程的中断状态设置为true而已,该线程所执行的程序还是会正常执行。
如果将stop换成interrupt,main方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws InterruptedException {
StopThread stopThread = new StopThread();
stopThread.start();
//休眠1秒,确保变量i自增成功
Thread.sleep(1000);
//中止线程
//stopThread.stop();
stopThread.interrupt();
while (stopThread.isAlive()){
//确保线程已经终止
}
//打印结果
stopThread.print();
}

代码执行结果如下:

—-模拟耗时结束——
i=1,j=1
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.sunnymaple.javabase.threadstop.StopThread.run(StopThread.java:18)

注意此时的结果不仅达到了我们预期的结果i=1,j=1,而且还抛出了InterruptedException异常,说明使用interrupt会抛出异常,让用户决定异常后如何处理,而不是像stop一样强行终止程序。

2.2、标志位

通过标志位,数值或者boolean,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class FlagStopThreadTest {
private volatile static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
try {
while (flag){
System.out.println("运行中");
Thread.sleep(1000);
}
}catch (InterruptedException e){
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
flag = false;
System.out.println("程序运行结束");
}
}

最后更新: 2019年09月15日 17:09

原始链接: https://www.sunnymaple.cn/2019/09/15/线程中止/

× 请我吃糖~
打赏二维码