您的位置:首页 > 运维架构

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

2017-09-04 17:13 381 查看
线程除了运行完毕,自动进入死亡状态,也可以手动进行停止,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语句中会再次添加中断标志。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: