from http://hapinwater.iteye.com/blog/310558
最近在學習Java線程相關的東西,和大家分享一下,有錯誤之處歡迎大家指正.
假如我們有一個任務如下,交給一個Java線程來執行,如何才能保證調用interrupt()來中斷它呢?
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //死循環執行打印"I am running!" 和做消耗時間的浮點計算
- while (true) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- //給線程調度器可以切換到其它進程的信號
- Thread.yield();
- }
- }
- }
- public class InterruptTaskTest {
- public static void main(String[] args) throws Exception{
- //將任務交給一個線程執行
- Thread t = new Thread(new ATask());
- t.start();
- //運行一斷時間中斷線程
- Thread.sleep(100);
- System.out.println("****************************");
- System.out.println("Interrupted Thread!");
- System.out.println("****************************");
- t.interrupt();
- }
- }
運行這個程序,我們發現調用interrupt()後,程序仍在運行,如果不強制結束,程序將一直運行下去,如下所示:
- ......
- I am running!
- I am running!
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- ....
雖然中斷髮生了,但線程仍然在進行,離開線程有兩種常用的方法:
拋出InterruptedException和用Thread.interrupted()檢查是否發生中斷,下面分別看一下這兩種方法:
1.在阻塞操作時如Thread.sleep()時被中斷會拋出InterruptedException(注意,進行不能中斷的IO操作而阻塞和要獲得對象的鎖調用對象的synchronized方法而阻塞時不會拋出InterruptedException)
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //死循環執行打印"I am running!" 和做消耗時間的浮點計算
- try {
- while (true) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- //休眠一斷時間,中斷時會拋出InterruptedException
- Thread.sleep(50);
- }
- } catch (InterruptedException e) {
- System.out.println("ATask.run() interrupted!");
- }
- }
- }
程序運行結果如下:
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!
可以看到中斷任務時讓任務拋出InterruptedException來離開任務.
2.Thread.interrupted()檢查是否發生中斷.Thread.interrupted()能告訴你線程是否發生中斷,並將清除中斷狀態標記,所以程序不會兩次通知你線程發生了中斷.
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- //檢查程序是否發生中斷
- while (!Thread.interrupted()) {
- System.out.println("I am running!");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- }
- System.out.println("ATask.run() interrupted!");
- }
- }
程序運行結果如下:
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!
我們可結合使用兩種方法來達到可以通過interrupt()中斷線程.請看下面例子:
- class ATask implements Runnable{
- private double d = 0.0;
- public void run() {
- try {
- //檢查程序是否發生中斷
- while (!Thread.interrupted()) {
- System.out.println("I am running!");
- //point1 before sleep
- Thread.sleep(20);
- //point2 after sleep
- System.out.println("Calculating");
- for (int i = 0; i < 900000; i++) {
- d = d + (Math.PI + Math.E) / d;
- }
- }
- } catch (InterruptedException e) {
- System.out.println("Exiting by Exception");
- }
- System.out.println("ATask.run() interrupted!");
- }
- }
在point1之前處point2之後發生中斷會產生兩種不同的結果,可以通過修改InterruptTaskTest main()裏的Thread.sleep()的時間來達到在point1之前產生中斷或在point2之後產生中斷.
如果在point1之前發生中斷,程序會在調用Thread.sleep()時拋出InterruptedException從而結束線程.這和在Thread.sleep()時被中斷是一樣的效果.程序運行結果可能如下:
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- ****************************
- Interrupted Thread!
- ****************************
- Exiting by Exception
- ATask.run() interrupted!
如果在point2之後發生中斷,線程會繼續執行到下一次while判斷中斷狀態時.程序運行結果可能如下:
- I am running!
- Calculating
- I am running!
- Calculating
- I am running!
- Calculating
- ****************************
- Interrupted Thread!
- ****************************
- ATask.run() interrupted!