java多線程-interrupt

java中的interrupt(中斷)很容易讓人產生歧義,僅從字面意思上理解是如果一個Thread實例調用了interrupt方法會中斷該線程。而事實並不是這樣,該方法知識爲我們提供了一種中斷的協作機制,真正什麼時候去中斷線程需要我們自己去定義中斷的邏輯。因爲interrupt方法僅僅是爲該線程設置了中斷標誌,並不會中斷線程,我們可以利用該中斷標誌來中斷該線程。

我們一般採用兩種方式中斷當前線程:

一種是利用阻塞方法sleep(),wait(),join(),這幾個方法會拋出InterruptException,當我們在調用了該線程的interrupt()方法時會拋出中斷異常,然後我們就可以設置合理的邏輯使線程線程中斷(我覺得用盡快跳出run方法,使任務提前結束來表述更爲貼切)。注意一點就是一旦產生了中斷異常後,線程的中斷標誌就會被自動清除(中斷狀態從true變爲false)

另外一種就是在任務中不斷檢測線程的中斷標誌來實現線程的中斷,java爲我們提供了兩個獲取中斷標誌的方法一個是Thread.interrupted()的靜態方法,另一個是isInterrupted()的實例方法,這兩個方法會返回線程的中斷狀態。

通過代碼來說明上面兩種中斷方法。

<span style="font-size:14px;">package com.lql.thread3;


/**
 * 通過阻塞方法拋出異常,當出現中斷時阻塞方法產生一箇中斷異常
 * 在異常處理中,採取合適的措施中斷線程
 * @author Administrator
 *
 */
public class MyInterrupt implements Runnable{
 
	private boolean flag = true;
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(flag){
			System.out.println("hello,world!");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block

				//產生中斷異常,在處理中斷異常時可以選擇終止本線程
				
				System.out.println("在阻塞的時候,檢測到中斷,會產生InterruptedException");
				
				//異常產生後,線程的中斷標誌會被標誌位false
				//所以Thread.interrupted()會返回false
				System.out.println("Thread.interrupted() " + Thread.interrupted());
				System.out.println("Thread.currentThread().isInterrupted() " +Thread.currentThread().isInterrupted());
				
				//在這裏修改標誌,將本線程終止,標誌位被修改後,當前線程就會跳出循環任務,之後線程就會被中斷
				flag = false;
			}
		}
		System.out.println(Thread.currentThread().getName() +"is stoped");
	}

}</span>
<span style="font-size:14px;">package com.lql.thread3;

public class InterruptTest {

	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new MyInterrupt());
		thread.start();
		
		//主線程休眠100毫秒,讓子線程可以執行一段時間
		Thread.sleep(100);
		
		//在主線程中調用子線程的interrupt()方法,置子線程的中斷標誌爲true
		//此時子線程的執行的sleep就會產生一箇中斷異常
		thread.interrupt();
	}
}</span>
運行結果
hello,world!
hello,world!
在阻塞的時候,檢測到中斷,會產生InterruptedException
Thread.interrupted() false
Thread.currentThread().isInterrupted() false
Thread-0is stoped

以上說明的是第一種中斷子線程的方式,即在阻塞方法的異常處理中加入合適的邏輯中斷線程


再來說明一下通過判斷標誌位狀態的方式終止線程的方式

package com.lql.thread3;

public class MyInterrupt2 implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		//通過不斷檢測線程的中斷標誌來判斷是否中斷當前線程的執行
		while(!Thread.currentThread().isInterrupted()){
			System.out.println("hello,world");
		}
		System.out.println(Thread.currentThread().getName()+ " is stop");
	}

}
package com.lql.thread3;

public class InterruptTest {

	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new MyInterrupt2());
		thread.start();
		
		//主線程休眠1毫秒,讓子線程可以執行一段時間
		Thread.sleep(1);
		
		thread.interrupt();
	}
}
hello,world
hello,world
hello,world
hello,world
hello,world
Thread-0 is stop
</pre><p><span style="font-size:14px;">可以看到子線程運行一段時間後同樣被中斷中斷了</span></p><p><span style="font-size:14px;"></span></p><p><span style="font-size:14px;">如果我們在子線程中加入一個阻塞方法比如sleep呢</span></p><p><span style="font-size:14px;"></span><pre name="code" class="java">package com.lql.thread3;

public class MyInterrupt2 implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		//通過不斷檢測線程的中斷標誌來判斷是否中斷當前線程的
		while(!Thread.currentThread().isInterrupted()){
			System.out.println("hello,world");
			
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		System.out.println(Thread.currentThread().getName()+ " is stop");
	}

}

運行可以看到子線程會一致運行下去,因爲主線程中調用子線程的interrupt()方法會使子線程的sleep方法產生一箇中斷異常,進而使該線程的中斷標誌清除(即中斷標誌變爲false)。所以子線程會一直運行下去。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章