1. 程式人生 > >簡單理解線程--阻塞,interrupt

簡單理解線程--阻塞,interrupt

log println 使用 pub 同時 static 數據 之前 必須

什麽是線程

  線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本不擁有資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進行所擁有的所有資源。

阻塞和非阻塞

  阻塞和非阻塞是形容多個線程之間的相互影響的(前提是多線程而不是一個),一個線程占用了臨界區資源,那麽其他線程必須在臨界區外等待,阻塞是操作系統層面掛起,上下文切換了,所以性能不高。如果一個線程一直占用不釋放資源,那麽其他需要該臨界區資源的線程都必須一直等待。非阻塞就是運行多個線程同時進入臨界區,只要保證不把數據修改壞就行。

阻塞的情況分三種:

  • 等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。
  • 同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。
  • 其他阻塞:運行的線程執行sleep()或join()方法時,或者發出I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時,join()等待線程終止或者超時,或者I/O處理完畢時,線程重新轉入就緒狀態。
 1 /*   
 2 
 3  * 如果線程被阻塞,它便不能核查共享變量,也就不能停止。這在許多情況下會發生,例如調用  
 4  * Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,他們都可能永  
5 * 久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使 6 * 用某種機制使得線程更早地退出被阻塞的狀態。很不幸運,不存在這樣一種機制對所有的情況 7 * 都適用,但是,根據情況不同卻可以使用特定的技術。使用Thread.interrupt()中斷線程 8 * Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法 9 * 實際上完成的是,在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態。更 10 * 確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麽,
11 * 它將接收到一個中斷異常(InterruptedException),從而提早地終結被阻塞狀態。因此, 12 * 如果線程被上述幾種方法阻塞,正確的停止線程方式是設置共享變量,並調用interrupt()(註 13 * 意變量應該先設置)。如果線程沒有被阻塞,這時調用interrupt()將不起作用;否則,線程就 14 * 將得到異常(該線程必須事先預備好處理此狀況),接著逃離阻塞狀態。在任何一種情況中,最 15 * 後線程都將檢查共享變量然後再停止。下面示例描述了該技術。 16 * */ 17 class Example extends Thread { 18 19 volatile boolean stop = false; 20 21 public static void main(String args[]) throws Exception { 22 Example thread = new Example(); 23 24 System.out.println("Starting thread..."); 25 thread.start(); 26 27 System.out.println("sleep 3S......"); 28 Thread.sleep(3000); 29 30 System.out.println("Asking thread to stop..."); 31 32 /* 33 * 如果線程阻塞,將不會檢查此變量,調用interrupt之後,線程就可以盡早的終結被阻塞狀態,能夠檢查這一變量。 34 */ 35 System.out.println("stop==true......"); 36 thread.stop = true; 37 38 39 /* 40 * 這一方法實際上完成的是,在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態 41 */ 42 System.out.println("interrupt......"); 43 thread.interrupt(); 44 45 Thread.sleep(3000); 46 System.out.println("Stopping application..."); 47 System.exit(0); 48 } 49 50 public void run() { 51 while (!stop) { 52 System.out.println("Thread running..."); 53 try { 54 System.out.println("sleep 2S......"); 55 Thread.sleep(2000); 56 } catch (InterruptedException e) { 57 // 接收到一個中斷異常(InterruptedException),從而提早地終結被阻塞狀態 58 System.out.println("Thread interrupted..."); 59 } 60 } 61 62 System.out.println("Thread exiting under request..."); 63 } 64 }

把握幾個重點:
stop變量、run方法中的sleep()、interrupt()、InterruptedException。串接起來就是這個意思:
  當我們在run方法中調用sleep(或其他阻塞線程的方法)時,如果線程阻塞的時間過長,比如10s,那在這10s內,線程阻塞,run方法不被執行,但是如果在這10s內,stop被設置成true,表明要終止這個線程,但是,現在線程是阻塞的,它的run方法不能執行,自然也就不能檢查stop,所以線程不能終止,這個時候,我們就可以用interrupt()方法了:我們在thread.stop = true;語句後調用thread.interrupt()方法, 該方法將在線程阻塞時拋出一個中斷信號,該信號將被catch語句捕獲到,一旦捕獲到這個信號,線程就提前終結自己的阻塞狀態,這樣,它就能夠再次運行run方法了,然後檢查到stop = true,while循環就不會再被執行,在執行了while後面的清理工作之後,run方法執行完 畢,線程終止。

http://mp.weixin.qq.com/s/1u95m2EcHFbbJNRv3GJlbQ

簡單理解線程--阻塞,interrupt