亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

對Java中interrupt、interrupted和isInterrupted的理解

asal 2016-11-17 12:54:49 1934
abstrak:今天在看到Thread類的isInterrupted方法可以獲取線程的中斷狀態(tài)于是寫了個例子想驗(yàn)證一下:public class Interrupt { public static void main(String[] args) throws Exception { Thread t

今天在看到Thread類的isInterrupted方法可以獲取線程的中斷狀態(tài)

QQ圖片20161117104700.png

于是寫了個例子想驗(yàn)證一下:

public class Interrupt {	public static void main(String[] args) throws Exception {
		Thread t = new Thread(new Worker());
		t.start();
		
		Thread.sleep(200);
		t.interrupt();
		
		System.out.println("Main thread stopped.");
	}	
	public static class Worker implements Runnable {		public void run() {
			System.out.println("Worker started.");			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				System.out.println("Worker IsInterrupted: " + 
						Thread.currentThread().isInterrupted());
			}
			
			System.out.println("Worker stopped.");
		}
	}
}

內(nèi)容很簡答:主線程main啟動了一個子線程Worker,然后讓worker睡500ms,而main睡200ms,之后main調(diào)用worker線程的interrupt方法去中斷worker,worker被中斷后打印中斷的狀態(tài)。下面是執(zhí)行結(jié)果:

Worker started.
Main thread stopped.
Worker IsInterrupted: falseWorker stopped.

Worker明明已經(jīng)被中斷,而isInterrupted()方法竟然返回了false,為什么呢?

在stackoverflow上搜索了一圈之后,發(fā)現(xiàn)有網(wǎng)友提到:可以查看拋出InterruptedException方法的JavaDoc(或源代碼),于是我查看了Thread.sleep方法的文檔,doc中是這樣描述這個InterruptedException異常的:

InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

注意到后面這句“當(dāng)拋出這個異常的時候,中斷狀態(tài)已被清除”。所以isInterrupted()方法應(yīng)該返回false??墒怯械臅r候,我們需要isInterrupted這個方法返回true,怎么辦呢?這里就要先說說interrupt, interrupted和isInterrupted的區(qū)別了:

interrupt方法是用于中斷線程的,調(diào)用該方法的線程的狀態(tài)將被置為"中斷"狀態(tài)。注意:線程中斷僅僅是設(shè)置線程的中斷狀態(tài)位,不會停止線程。需要用戶自己去監(jiān)視線程的狀態(tài)為并做處理。支持線程中斷的方法(也就是線程中斷后會拋出InterruptedException的方法,比如這里的sleep,以及Object.wait等方法)就是在監(jiān)視線程的中斷狀態(tài),一旦線程的中斷狀態(tài)被置為“中斷狀態(tài)”,就會拋出中斷異常。

interrupt() merely sets the thread's interruption status. Code running in the interrupted thread can later poll the interrupted status to see if it has been requested to stop what it is doing

再來看看interrupted方法的實(shí)現(xiàn):

public static boolean interrupted() {   
 return currentThread().isInterrupted(true);
}

和isInterrupted的實(shí)現(xiàn):

public boolean isInterrupted() {  
  return isInterrupted(false);
}

這兩個方法一個是static的,一個不是,但實(shí)際上都是在調(diào)用同一個方法,只是interrupted方法傳入的參數(shù)為true,而inInterrupted傳入的參數(shù)為false。那么這個參數(shù)到底是什么意思呢?來看下這個isInterrupted(boolean)方法的實(shí)現(xiàn):

/**
 * Tests if some Thread has been interrupted.  The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */private native boolean isInterrupted(boolean ClearInterrupted);

這是一個native方法,看不到源碼沒有關(guān)系,參數(shù)名字ClearInterrupted已經(jīng)清楚的表達(dá)了該參數(shù)的作用----是否清除中斷狀態(tài)。方法的注釋也清晰的表達(dá)了“中斷狀態(tài)將會根據(jù)傳入的ClearInterrupted參數(shù)值確定是否重置”。所以,靜態(tài)方法interrupted將會清除中斷狀態(tài)(傳入的參數(shù)ClearInterrupted為true),而實(shí)例方法isInterrupted則不會(傳入的參數(shù)ClearInterrupted為false)。

回到剛剛的問題:很明顯,如果要isInterrupted這個方法返回true,通過在調(diào)用isInterrupted方法之前再次調(diào)用interrupt()方法來恢復(fù)這個中斷的狀態(tài)即可:

public class Interrupt  {	public static void main(String[] args) throws Exception {
		Thread t = new Thread(new Worker());
		t.start();
		
		Thread.sleep(200);
		t.interrupt();
		
		System.out.println("Main thread stopped.");
	}	
	public static class Worker implements Runnable {		public void run() {
			System.out.println("Worker started.");			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				Thread curr = Thread.currentThread();				//再次調(diào)用interrupt方法中斷自己,將中斷狀態(tài)設(shè)置為“中斷”
				curr.interrupt();
				System.out.println("Worker IsInterrupted: " + curr.isInterrupted());
				System.out.println("Worker IsInterrupted: " + curr.isInterrupted());
				System.out.println("Static Call: " + Thread.interrupted());//clear status
				System.out.println("---------After Interrupt Status Cleared----------");
				System.out.println("Static Call: " + Thread.interrupted());
				System.out.println("Worker IsInterrupted: " + curr.isInterrupted());
				System.out.println("Worker IsInterrupted: " + curr.isInterrupted());
			}
			
			System.out.println("Worker stopped.");
		}
	}

執(zhí)行結(jié)果:

Worker started.
Main thread stopped.
Worker IsInterrupted: trueWorker IsInterrupted: trueStatic Call: true---------After Interrupt Status Cleared----------
Static Call: falseWorker IsInterrupted: falseWorker IsInterrupted: falseWorker stopped.

從執(zhí)行結(jié)果也可以看到,前兩次調(diào)用isInterrupted方法都返回true,說明isInterrupted方法不會改變線程的中斷狀態(tài),而接下來調(diào)用靜態(tài)的interrupted()方法,第一次返回了true,表示線程被中斷,第二次則返回了false,因?yàn)榈谝淮握{(diào)用的時候已經(jīng)清除了中斷狀態(tài)。最后兩次調(diào)用isInterrupted()方法就肯定返回false了。

那么,在什么場景下,我們需要在catch塊里面中斷線程(重置中斷狀態(tài))呢?

答案是:如果不能拋出InterruptedException(就像這里的Thread.sleep語句放在了Runnable的run方法中,這個方法不允許拋出任何受檢查的異常),但又想告訴上層調(diào)用者這里發(fā)生了中斷的時候,就只能在catch里面重置中斷狀態(tài)了。

If you catch InterruptedException but cannot rethrow it, you should preserve evidence that the interruption occurred so that code higher up on the call stack can learn of the interruption and respond to it if it wants to. This task is accomplished by calling interrupt() to "reinterrupt" the current thread, as shown in Listing 3.

 Listing 3: Restoring the interrupted status after catching InterruptedException

public class TaskRunner implements Runnable {    private BlockingQueue<Task> queue; 
    public TaskRunner(BlockingQueue<Task> queue) { 
        this.queue = queue; 
    } 
    public void run() { 
        try {             while (true) {
                 Task task = queue.take(10, TimeUnit.SECONDS);
                 task.execute();
             }
         } catch (InterruptedException e) { 
             // Restore the interrupted status
             Thread.currentThread().interrupt();
         }
    }
}

那么問題來了:為什么要在拋出InterruptedException的時候清除掉中斷狀態(tài)呢?

這個問題沒有找到官方的解釋,估計只有Java設(shè)計者們才能回答了。但這解釋似乎比較合理:一個中斷應(yīng)該只被處理一次(你catch了這個InterruptedException,說明你能處理這個異常,你不希望上層調(diào)用者看到這個中斷)。


Nota Keluaran

Penyertaan Popular