1. 程式人生 > >線程的終止stop與線程的中斷interrupted

線程的終止stop與線程的中斷interrupted

需要 run sed ktr alt 技術分享 進程 lee blog

線程除了運行完畢,自動進入死亡狀態,也可以手動進行停止,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