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

来源:互联网 发布:养生软件下载排行榜 编辑:程序博客网 时间:2024/06/05 04:48

线程除了运行完毕,自动进入死亡状态,也可以手动进行停止,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         @Override31         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         @Override47         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         @Override73         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语句中会再次添加中断标志。

原创粉丝点击