1 interrup關於interrupt javajdk文檔描述如下
interrupt()的作用是中斷本線程
本線程中斷自己是被允許的;其他線程調用本線程的interrupt()方法時,會通過checkAccess()檢察權限,這有可能跑出SecurityException異常
如果本線程是處於阻塞狀態:調用線程的wait() wait(long,int) 會讓它進入等待(阻塞)狀態,或者調用線程的join() sleep()也會讓他進入阻塞狀態,若線程在阻塞狀態時,調用了它的interrupt()方法,那麼它的"中斷狀態"會被清除,並且會收到一個InterruptedException異常。例如,線程通過wait()進入阻塞狀態。例如,線程通過wait()進入阻塞狀態,此時通過interrupt()中斷線程,調用interrupt()會立即將線程的中斷標記設爲"true",但是由於線程處於阻塞狀態,所以該"中斷標記"會立即被清除爲"false",同時會產生一個InterruptedException的異常,如果線程被阻塞在一個Selector選擇器中,那麼通過interrupt()中斷它時,線程的中斷標記會被設置爲true,並且他會立即從選擇操作中返回
如果不屬於前面所說的情況,那麼通過interrupt()中斷線程時,它的中斷標記會被設置爲"tru
中斷一個"已終止的線程"不會產生任何操作
2 終止線程的方式
Thread中的stop()和suspend()方法,由於固有的不安全性,已經不建議使用
下面,我先分別討論線程在"阻塞狀態","運行狀態"的終止方式,然後再總結出一個通用的方式
2.1 終止處於阻塞狀態的線程
通常,我們通過"中斷"方式終止處於"阻塞狀態"的線程
當線程由於被調用了sleep(),wait(),join()等方法而進入阻塞狀態;若此時調用線程的interrupt()線程中的中斷標記設爲true 由於處於阻塞狀態,中斷標記會被清除,同時產生一個interruptedException異常,將interruptedException放在適當的爲止就能終止線程,形式如下。
@Override
public void run() {
try {
while (true) {
// 執行任務...
}
} catch (InterruptedException ie) {
// 由於產生InterruptedException異常,退出while(true)循環,線程終止!
}
}
說明:在while(true)中不斷的執行任務,當線程處於阻塞狀態時,調用線程的interrupt()產生InterruptedException中斷。中斷的捕獲在while(true)之外,這樣就退出了while(true)循環!
注意:對InterruptedException的捕獲務一般放在while(true)循環體的外面,這樣,在產生異常時就退出了while(true)循環。否則,InterruptedException在while(true)循環體之內,就需要額外的添加退出處理。形式如下:
@Override
public void run() {
while (true) {
try {
// 執行任務...
} catch (InterruptedException ie) {
// InterruptedException在while(true)循環體內。
// 當線程產生了InterruptedException異常時,while(true)仍能繼續運行!需要手動退出
break;
}
}
}
說明:上面的InterruptedException異常的捕獲在whle(true)之內。當產生InterruptedException異常時,被catch處理之外,仍然在while(true)循環體內;要退出while(true)循環體,需要額外的執行退出while(true)的操作。
2.2終止chuyu"運行狀態"的線程。其中包括"中斷標記" "額外添加標記"
01 通過"中斷標記"終止線程
@Override
public void run() {
while (!isInterrupted()) {
// 執行任務...
}
}
說明:isInterrupted()是判斷線程的中斷標記是不是爲true。當線程處於運行狀態,並且我們需要終止它時,可以調用線程的interrupt()方法,使用線程的中斷標記爲true,即isInterrupted()會返回true。此時,就會退出while循環
注意 每個線程都會有一箇中斷標記,在run方法中加以判斷,interrupt()並不會處於"運行狀態"的線程 它會將線程的中斷標記設爲true
02 通過"額外添加標記"
private volatile boolean flag= true;
protected void stopTask() {
flag = false;
}
@Override
public void run() {
while (flag) {
// 執行任務...
}
}
線程中有一個flag標記,它的默認值是true;並且我們提供stopTask()來設置flag標記,當我們需要終止該線程時,調用該線程的stopTask()方法就可以讓線程退出while循環,將flag定義爲volatile類型,是爲了保證flag的可見性.ji其他線程通過,stopTask()修改了flag之後,本線程就能剛看到修改後的flag的值。
綜合線程處於"阻塞狀態"和"運行狀態"的終止方式,比較通用的終止線程的形式如下
@Override
public void run() {
try {
// 1. isInterrupted()保證,只要中斷標記爲true就終止線程。
while (!isInterrupted()) {
// 執行任務...
}
} catch (InterruptedException ie) {
// 2. InterruptedException異常保證,當InterruptedException異常產生時,線程被終止。
}
}
3 終止線程的示例
package com.tuhu.filt.javadatasleep;
public class Demo1 {
public static void main(String[] args) {
try{
Thread t1 = new MyThread("t1");
System.out.println(
t1.getName()
+" ("
+t1.getState()
+") is new."
);
t1.start();
System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
Thread.sleep(300);
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
class MyThread extends Thread{
public MyThread(String name){
super(name);
}
public void run(){
try{
int i = 0;
while(! isInterrupted()){
Thread.sleep(100);//休眠100ms
i++;
System.out.println(
Thread.currentThread().getName()
+" ("
+this.getState()+") loop"
+ i
);
}
}catch (InterruptedException e){
System.out.println(
Thread.currentThread().getName()
+ " ("+this.getState()+") catch InterruptedException."
);
}
}
}
t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop1
t1 (RUNNABLE) loop2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) catch InterruptedException.
t1 (TERMINATED) is interrupted now.
01 主線程main中通過new MyThread("t1")創建線程t1,之後t1.start()啓動線程t1
02 t1啓動之後,會不斷檢查它的中斷標記,如果中斷標記爲"false";則休眠100ms
03 t1休眠之後,會切換到主線程main;主線程再次運行,會執行t1.interrupt()中斷線程t1,t1收到中斷指令之後,會將t1的中斷標記設置爲"false",而且會拋出異常我們將捕獲異常的代碼塊移到while循環體內
// Demo2.java的源碼
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
int i=0;
while (!isInterrupted()) {
try {
Thread.sleep(100); // 休眠100ms
} catch (InterruptedException ie) {
System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
}
i++;
System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
}
}
}
public class Demo2 {
public static void main(String[] args) {
try {
Thread t1 = new MyThread("t1"); // 新建“線程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
t1.start(); // 啓動“線程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
// 主線程休眠300ms,然後主線程給t1發“中斷”指令。
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
// 主線程休眠300ms,然後查看t1的狀態。
Thread.sleep(300);
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) catch InterruptedException.
t1 (RUNNABLE) loop 3
t1 (RUNNABLE) loop 4
t1 (RUNNABLE) loop 5
t1 (TIMED_WAITING) is interrupted now.
t1 (RUNNABLE) loop 6
t1 (RUNNABLE) loop 7
t1 (RUNNABLE) loop 8
t1 (RUNNABLE) loop 9
...
很顯然程序進入了死循環
下面通過額外加標記終止狀態線程的示例
// Demo3.java的源碼
class MyThread extends Thread {
private volatile boolean flag= true;
public void stopTask() {
flag = false;
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
synchronized(this) {
try {
int i=0;
while (flag) {
Thread.sleep(100); // 休眠100ms
i++;
System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
}
} catch (InterruptedException ie) {
System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
}
}
}
}
public class Demo3 {
public static void main(String[] args) {
try {
MyThread t1 = new MyThread("t1"); // 新建“線程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
t1.start(); // 啓動“線程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
// 主線程休眠300ms,然後主線程給t1發“中斷”指令。
Thread.sleep(300);
t1.stopTask();
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
// 主線程休眠300ms,然後查看t1的狀態。
Thread.sleep(300);
System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) loop 3
t1 (TERMINATED) is interrupted now.
4 interrupted() 和 isInterrupted()的區別
interrupted() 和 isInterrupted()都能夠用於檢測對象的中斷標記
區別是 interrupted()除了返回中斷標記之外,他還會中斷標記(即將中斷標記設爲false),
而isInterrupted()僅僅返回中斷標記