併發 · 四 —— 線程狀態 和 阻塞時中斷的 interrupt()方法

線程有四種狀態:新建、就緒、阻塞和死亡。

1)新建:當線程被創建時,它只會短暫地處於這種狀態,在這段時間內,主要會執行一些初始化的的操作。

2)就緒:在這種狀態下,只要調度器把時間片分配給線程,該線程就可以運行了。

3)阻塞:線程能夠運行,但是有某個條件阻止它的運行。當線程處於阻塞狀態時,調度器將忽略線程,不會分配給線程任何的CPU時間。直到線程重新進入了就緒的狀態,調度器纔會繼續分配CPU時間給它。

4)死亡:處於該狀態的線程將不再是可調度的,並且再也不會得到CPU時間,它的任務已結束了。任務死亡的通常方式是從run()方法返回。

注意:線程中的stop()方法已經被棄用了,主要是因爲它不釋放線程獲取的鎖,並且如果線程處於不一致的狀態,其它任務可以在這種狀態下瀏覽並修改它們,這樣鎖產生的問題就很難被發現了。

進入阻塞狀態幾種方式:

1)通過調用sleep(millisecond)使任務進入休眠狀態,在這種情況下,任務在指定的時間內處於阻塞狀態,不會獲得CPU時間,並且不會釋放線程自身所持有的鎖(區別於調用wait()將線程掛起)。

2)調用wait()使線程掛起,直到線程得到了notify()或notifyAll()消息,線程重新纔會進入就緒狀態。

3)任務在等待某個輸入/輸出完成。

4)任務試圖在某個對象上調用其同步控制方法,但是對象鎖不同,此時就會被阻塞了。

**中斷

常規手動停止線程的方法就是通過設置標誌位的方法或者到達預先埋好的返回代碼的位置,切記,stop()方法已經棄用了,由於不穩定,無法正常釋放鎖

public class text1 {
	
	volatile static boolean stop = false;
	
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (!stop) {
					System.out.println("運行中。。");
				}
			}
		}).start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		stop = true;
	}
}

1、interrupt()

在Thread類提供interrupt()方法,用於中止正在被阻塞的任務。當打斷一個正在被阻塞的任務時,通常還需要清理資源,這正如處理拋出異常,由於有這種需求存在,Java在設計阻塞時中斷方法時,即在調用interrupt()設置線程爲中斷狀態後,如果線程遇到阻塞就會拋出InterruptedException異常,並且將會重置線程的中斷狀態。例如

public class text2 {
	
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt();// 將線程設置爲中斷狀態
				
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打斷");
					// 在這裏清理資源
					e.printStackTrace();
				}
				
				System.out.println("又遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打斷");
					// 在這裏清理資源
					e.printStackTrace();
				}
				System.out.println("結束線程");
			}
		}.start();
	}
}

>> 運行的結果

遇到阻塞
阻塞被打斷
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at text$1.run(text.java:19)
又遇到阻塞
結束線程

>>

從運行結果,我們可以看出,在調用interrupt()方法線程就被設置爲中斷狀態,一旦遇到阻塞,就會立馬中斷阻塞,並拋出異常,並且重置中斷狀態位,當下次遇到阻塞就不會被中斷並拋出異常。可以這麼理解,調用interrupt(),便將線程的中斷標誌位置爲true,當遇到阻塞(或者在調用interrupt方法中,正處於阻塞),都會立馬中斷阻塞,將線程的中斷標誌位置爲false,並拋出異常。

public class text3 {
	public static void main(String[] args) {
		Thread t = new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打斷");
					// 在這裏清理資源
					e.printStackTrace();
				}
				System.out.println("阻塞結束");
				System.out.println("結束線程");
			}
		};
		t.start();
		try {
			Thread.sleep(500); // 爲了確保線程已經運行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("調用interrupt()");
		t.interrupt();
	}
}

>> 運行結果

遇到阻塞
調用interrupt()
阻塞被打斷
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at text$1.run(text.java:17)
阻塞結束
結束線程

>>

正如上面的運行結果可以看出,如果線程正處於阻塞狀態,調用interrupt()方法,會立馬打斷阻塞並拋出異常。

2、Thread.interrupted();

 除了遇到阻塞會拋出異常,並重置線程中斷狀態,Thread還有提供了一個interrupted()的靜態方法,可以將當前的線程的中斷狀態重置。將上面第一個例子text1改進一下,它將不會阻塞被中斷

public class text1_1 {
	
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt(); // 將線程置爲中斷狀態
				Thread.interrupted(); // 重置線程中斷狀態
				System.out.println("遇到阻塞");				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("阻塞被打斷");
					// 在這裏清理資源
					e.printStackTrace();
				}
				System.out.println("阻塞結束");
				System.out.println("結束線程");
			}
		}.start();
		
	}

>> 運行結果

遇到阻塞
阻塞結束
結束線程

>>

3、isInterrupted()

可以通過調用這個方法打印當前線程的中斷狀態

public class text4 {
	public static void main(String[] args) {
		new Thread(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				super.run();
				interrupt(); // 設置中斷狀態
				System.out.println(interrupted()); // 打印中斷狀態
			}
		}.start();
		
	}
}

>>運行結果

true
>>

注意:當I/O和synchronized塊上的等待是不可中斷的的,也不需要InterruptException處理器。中斷可以打斷的有調用sleep()、調用wait()調起將線程掛起。

 

正文到這就完,哈哈哈,這篇主要是總結一些概念的東西,沒有太難理解的地方,emmmm,寫這篇還有個原因,是爲得一下那個持之以恆的獎章,嘻嘻嘻嘻

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