线程的终止stop与线程的中断interrupted

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程的终止stop与线程的中断interrupted相关的知识,希望对你有一定的参考价值。

线程除了运行完毕,自动进入死亡状态,也可以手动进行停止,Thread类也提供了2个类方法来进行线程的停止。

技术分享

 

 一、stop

如图所示,stop方法已经被标记为过时的,不推荐的。因为这这个方法太过于暴力,会立即杀死进程,导致数据不能同步,带来很难排查的错误。

下面是一段造成错误信息的代码:

技术分享
 1 public class StopThreadUnsafe {
 2     public static User u = new User();
 3 
 4     public static class User {
 5         private int id;
 6         private String name;
 7 
 8 
 9         public User() {
10             this.id = 0;
11             this.name = "0";
12         }
13 
14         public int getId() {
15             return id;
16         }
17 
18         public void setId(int id) {
19             this.id = id;
20         }
21 
22         public String getName() {
23             return name;
24         }
25 
26         public void setName(String name) {
27             this.name = name;
28         }
29 
30         @Override
31         public String toString() {
32             return "User{" +
33                     "id=" + id +
34                     ", name=‘" + name + ‘\\‘‘ +
35                     ‘}‘;
36         }
37     }
38 
39     public static class ChangeObjectThread extends Thread {
40         volatile boolean stopme = false;
41 
42         public void stopMe() {
43             stopme = true;
44         }
45 
46         @Override
47         public void run() {
48             while (true) {
49 //                if (stopme) {
50 //                    System.out.println("exit by stop me ");
51 //                    break;
52 //                }
53                 synchronized (u) {
54                     int v = (int) (System.currentTimeMillis() / 1000);
55                     u.setId(v);
56                     //暂停一段时间
57 
58                     try {
59                         Thread.sleep(100);
60                     } catch (InterruptedException e) {
61                         e.printStackTrace();
62                     }
63                     //暂停之后再写入值
64                     u.setName(String.valueOf(v));
65                 }
66                 Thread.yield();
67             }
68         }
69     }
70 
71     public static class ReadObjectThread extends Thread {
72         @Override
73         public void run() {
74             while (true) {
75                 synchronized (u) {
76                     if (u.getId() != Integer.parseInt(u.getName())) {
77                         System.out.println(u.toString());
78                     }
79                 }
80                 Thread.yield();
81             }
82         }
83     }
84 
85 
86     public static void main(String[] args) throws InterruptedException {
87         new ReadObjectThread().start();
88         while (true) {
89             Thread t = new ChangeObjectThread();
90             t.start();
91             Thread.sleep(150);
92             t.stop();
93         }
94     }
95 }
错误代码

运行起来的结果是:

里面情况是id和name是同一个值,但是被强行stop掉了线程,导致数据混乱。

技术分享

那么如何停止一个线程呢?

在线程体中加一个flag,每次执行线程体时查看标杆,如果标杆有效,则自动退出,如代码中,就有一个stopme方法,在合适的时候调用就可以停止线程,而且是缓和的,基本上不会带来数据丢失的问题。

 二、interrupt

stop既然这么坑,所有JDK还是给了解决办法的,那就是线程中断Interrupt。

技术分享

JDK里面有4个关于interrupt的方法,

public void interrupt() 
中断线程,该方法是一个实例方法,它通知目标线程中断,也就是设置中断标志位。,中断标志位标识当前线程已经被中断了。
tips:给线程加了中断,并不会对线程起实质性作用,仅仅是设置了中断标志位,还需要进行一系列退出操作才可以进行线程的终止。
public boolean isInterrupted()
判断当前线程是否有被中断,通过检查中断标志位来判断。
public static boolean interrupted()
interrupted也是用来判断当前线程的中断状态,但同时会清除当前能线程的中断标志位状态。
private native boolean isInterrupted(boolean ClearInterrupted)

代码示例:

技术分享
 1 /**
 2  * 关于中断Interrupt
 3  * Created by huxingyue on 2017/9/3.
 4  */
 5 public class InterruptAbout {
 6     public static void main(String[] args) throws InterruptedException {
 7         Thread t1 = new Thread() {
 8             @Override
 9             public void run() {
10                 while (true) {
11                     //这才是合理的退出
12                     if (Thread.currentThread().isInterrupted()) {
13                         System.out.println("here is interrupted ");
14                         break;
15                     }
16                     System.out.println("这里执行了一次yield");
17 
18                     System.out.println("1当前线程是中断状态吗?"+Thread.currentThread().isInterrupted());
19                     try {
20                         System.out.println("此处准备睡眠");
21                         Thread.sleep(2000);
22                     } catch (InterruptedException e) {
23                         System.out.println("interrupted when sleep");
24                         //应该在这里再次加中断,sleep报出异常后会清除中断标志
25                         System.out.println("2当前线程是中断状态吗?"+Thread.currentThread().isInterrupted());
26                         Thread.currentThread().interrupt();
27                     }
28 
29 
30                     Thread.yield();
31                 }
32             }
33         };
34         t1.start();
35         Thread.sleep(2000);
36         t1.interrupt();
37     }
38 }
View Code

while里面加了一个if去判断线程的中断标志位,如果有中断标志的话,就可以合理退出。

值的注意的是,当调用sleep()时,可能被interrupt()方法打断,这这时就会抛出InterruptedException,不仅仅是会抛出异常,而且还会清除标志位,所以在catch语句中会再次添加中断标志。



以上是关于线程的终止stop与线程的中断interrupted的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程-如何终止线程

java 多线程6: 中断机制 优雅的终止java线程

Java--终止/中断线程

详解线程interrupt()方法

线程停止(stop() interrupt() interrupted() isInterrupted())

线程的终止