我的家園

          我的家園

          [本文是我對(duì)Java Concurrency In Practice 7.1的歸納和總結(jié). ?轉(zhuǎn)載請(qǐng)注明作者和出處, ?如有謬誤, 歡迎在評(píng)論中指正. ]

          ?

          在java的中斷機(jī)制中, InterruptedException異常占據(jù)重要的位置. 處理InterruptedException異常的方式有:

          ?

          1. 不catch直接向上層拋出, 或者catch住做一些清理工作之后重拋該異常. 這樣的處理使得你的方法也成為一個(gè)可中斷的阻塞方法:

          // 直接向上層拋出InterruptedException, dosomething方法也是一個(gè)可中斷的阻塞方法
          private void dosomething() throws InterruptedException {
          	Thread.sleep(1000);
          }
          ??

          2. 有時(shí)不能向上拋出InterruptedException異常(例如父類的相應(yīng)方法沒(méi)有聲明該異常), 此時(shí)catch之后, 必須設(shè)置當(dāng)前線程的中斷標(biāo)記為true, 以表明當(dāng)前線程發(fā)生了中斷, 以便調(diào)用棧上層進(jìn)行處理:

          public class InterruptedExceptionHandler implements Runnable {
          	private Object lock = new Object();
          
          	@Override
          	public void run() {
          		while (!Thread.currentThread().isInterrupted()) {
          			dosomething();
          		}
          	}
          
          	private void dosomething() {
          		try {
          			// Object.wait是一個(gè)可中斷的阻塞方法, 如果在其阻塞期間檢查到當(dāng)前線程的中斷標(biāo)記為true, 會(huì)重置中斷標(biāo)記后從阻塞狀態(tài)返回, 并拋出InterruptedException異常
          			synchronized (lock) {
          				lock.wait();
          			}
          		} catch (InterruptedException e) {
          			System.out.println("InterruptedException happened");
          			// catch住InterruptedException后設(shè)置當(dāng)前線程的中斷標(biāo)記為true, 以供調(diào)用棧上層進(jìn)行相應(yīng)的處理
          			// 在此例中, dosomething方法的調(diào)用棧上層是run方法.
          			Thread.currentThread().interrupt();
          		}
          	}
          	
          	public static void main(String[] args) throws InterruptedException {
          		Thread t = new Thread(new InterruptedExceptionHandler());
          		t.start();
          		// 啟動(dòng)線程1s后設(shè)置其中斷標(biāo)記為true
          		Thread.sleep(1000);
          		t.interrupt();
          	}
          }?

          主線程啟動(dòng)InterruptedExceptionHandler線程1s后, 設(shè)置InterruptedExceptionHandler線程的中斷標(biāo)記為true. 此時(shí)InterruptedExceptionHandler線程應(yīng)該阻塞在wait方法上, 由于wait方法是可中斷的阻塞方法, 所以其檢查到中斷標(biāo)記為true時(shí), 將重置當(dāng)前線程的中斷標(biāo)記后拋出InterruptedException, dosomething方法catch住InterruptedException異常后, 再次將當(dāng)前線程的中斷標(biāo)記設(shè)置為true, run方法檢查到中斷標(biāo)記為true, 循環(huán)不再繼續(xù). 假如dosomething方法catch住InterruptedException異常后沒(méi)有設(shè)置中斷標(biāo)記, 其調(diào)用棧上層的run方法就無(wú)法得知線程曾經(jīng)發(fā)生過(guò)中斷, 循環(huán)也就無(wú)法終止.

          ?

          3. 還有一種情形比較特殊: 我們希望發(fā)生了InterruptedException異常后仍然繼續(xù)循環(huán)執(zhí)行某阻塞方法, 此時(shí)應(yīng)該將中斷狀態(tài)保存下來(lái), 當(dāng)循環(huán)完成后再根據(jù)保存下來(lái)的中斷狀態(tài)執(zhí)行相應(yīng)的操作:

          public class InterruptedExceptionContinueHandler implements Runnable {
          	private BlockingQueue<Integer> queue;
          
          	public InterruptedExceptionContinueHandler(BlockingQueue<Integer> queue) {
          		this.queue = queue;
          	}
          
          	@Override
          	public void run() {
          		while (!Thread.currentThread().isInterrupted()) {
          			dosomething();
          		}
          		System.out.println(queue.size());
          	}
          
          	private void dosomething() {
          		// cancelled變量用于表明線程是否發(fā)生過(guò)中斷
          		boolean cancelled = false;
          		for (int i = 0; i < 10000; i++) {
          			try {
          				queue.put(i);
          			} catch (InterruptedException e) {
          				// 就算發(fā)生了InterruptedException, 循環(huán)也希望繼續(xù)運(yùn)行下去, 此時(shí)將cancelled設(shè)置為true, 以表明遍歷過(guò)程中發(fā)生了中斷
          				System.out.println("InterruptedException happened when i = " + i);
          				cancelled = true;
          			}
          		}
          		// 如果當(dāng)前線程曾經(jīng)發(fā)生過(guò)中斷, 就將其中斷標(biāo)記設(shè)置為true, 以通知dosomething方法的上層調(diào)用棧
          		if (cancelled) {
          			Thread.currentThread().interrupt();
          		}
          	}
          	
          	public static void main(String[] args) throws InterruptedException {
          		Thread t = new Thread(new InterruptedExceptionContinueHandler(new LinkedBlockingQueue<Integer>()));
          		t.start();
          		
          		// 啟動(dòng)線程2ms后設(shè)置其中斷標(biāo)記為true
          		Thread.sleep(2);
          		t.interrupt();
          	}
          }

          在我的機(jī)器中, 輸出結(jié)果如下:

          InterruptedException happened when i = 936

          size = 9999

          隊(duì)列的size是9999而不是10000, 是因?yàn)閕 = 936時(shí)發(fā)生了InterruptedException異常, 該次put沒(méi)有成功.

          為什么不在發(fā)生InterruptedException時(shí)就設(shè)置當(dāng)前線程的中斷標(biāo)記, 而非要繞一圈? 假設(shè)將dosomething方法改為:

          private void dosomething() {
          	for (int i = 0; i < 10000; i++) {
          		try {
          			queue.put(i);
          		} catch (InterruptedException e) {
          			System.out.println("InterruptedException happened when i = " + i);
          			Thread.currentThread().interrupt();
          		}
          	}
          }

          運(yùn)行后發(fā)現(xiàn)結(jié)果類似為:

          InterruptedException happened when i = 936

          InterruptedException happened when i = 937

          ...

          InterruptedException happened when i = 9998

          InterruptedException happened when i = 9999

          size = 936

          catch住InterruptedException后立即將當(dāng)前線程的中斷標(biāo)記設(shè)置為true, 就會(huì)導(dǎo)致put方法又拋出InterruptedException異常, 如此往復(fù)直到循環(huán)結(jié)束.

          ?

          4. 最不可取的是catch了InterruptedException異常但是不做任何處理, 這樣一來(lái)調(diào)用棧上層就無(wú)法得知當(dāng)前線程是否發(fā)生過(guò)中斷. 只有一種情況下可以這樣處理: 當(dāng)InterruptedException發(fā)生在調(diào)用棧的最上層, 如run方法, 或者main方法中, 且后續(xù)代碼不檢查中斷狀態(tài)時(shí):

          public static void main(String[] args) {
          	// main方法已經(jīng)是調(diào)用棧的最上層, 此時(shí)可以catchInterruptedException后不做任何處理
          	try {
          		Thread.sleep(2);
          	} catch (InterruptedException e) {
          		e.printStackTrace();
          	}
          }





          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 习水县| 山丹县| 桐庐县| 伊川县| 理塘县| 钦州市| 余姚市| 南充市| 南阳市| 万宁市| 泰兴市| 龙门县| 天镇县| 宁国市| 西峡县| 水富县| 莫力| 交口县| 宜兰县| 承德市| 横峰县| 渑池县| 东辽县| 德安县| 绥化市| 鄂托克旗| 天津市| 宁安市| 东辽县| 河源市| 柯坪县| 垣曲县| 石林| 巫山县| 保康县| 舞阳县| 泾源县| 阿尔山市| 义乌市| 施秉县| 铁岭县|