標題中的幾個概念大概設計到線程同步以及線程阻塞這兩個概念。線程同步,就是同一時刻,只有一個線程能執行指定的代碼;另外一個線程阻塞就是當前線程暫時停在某個位置,等待某個條件成立之后再繼續往下面執行。
線程同步就是,是為了控制多線程工作存在的並發造成共享資源競爭的問題。java中可以通過加鎖(monitor)的方式來控制,其實就是兩個關鍵字,一個是synchronized,另外一個是lock,關於這兩個的區別,請自行google。其中wait方法就必須獲取某個對象的monitor之后,才允許執行,否則會跑出monitor status不正確的異常。wait()和join()方法是屬於Object的實例方法。wait()方法必須放在同步代碼塊之內(如下),即是表示獲得了某個對象的monitor(鎖)之后,才允許執行該對象的wait()方法;執行了wait()方法之后,當前線程會處於阻塞狀態,這時候當前線程會釋放進來的時候獲取的指定對象的monitor(鎖),同時讓出cpu,不在參與cpu的競爭,等待其他線程執行指定對象的notify()或者notifyAll()方法來將其喚醒,以繼續執行下去(被喚醒之后,也要先獲取指定對象的鎖才會進來,因為同步塊進來之前必須是獲取了指定對象的monitor,同時,不是從新執行,獲得monitor之后,是從之前wait()那里開始繼續網下面執行,因為之前在這里阻塞了,cpu相關的寄存在會記住之前阻塞的位置的)。
public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName()); lock.wait(); if (Thread.currentThread().getName().equals("Thread-1")) { Thread.sleep(50000); } System.out.println("end wait() ThreadName=" + Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void synNotifyMethod(Object lock) { synchronized (lock) { System.out.println("begin notify() ThreadName=" + Thread.currentThread().getName()); lock.notifyAll(); System.out.println("end notify() ThreadName=" + Thread.currentThread().getName()); } } }
至於interrupt()方法和InterruptException異常,是java專門用來處理線程阻塞的。線程阻塞,就表示要等待一段時間。如果需要等待的時間比較長,正常還沒結束之前想中斷某個線程的阻塞狀態怎么辦?這就是靠interrupt()方法來解決了。如果因為一些特殊的原因,想提前中斷一些阻塞的線程,以讓他們提前解除阻塞狀態,然后繼續執行下去。只需要在其他線程調用指定線程的interrupt()方法即可(interrupt()方法是線程實例方法),這時候原來阻塞的對應的線程就會拋出InterruptException異常,通過catch捕獲異常就可以繼續往下面執行了。比如線程方法sleep()和Object的實例方法wait(),都會導致當前線程阻塞,這時候就可以通過interrupt()方法來提前退出阻塞狀態。
為什么Interrupt()方法可以提前中斷阻塞呢?其實是因為每個線程都會有一個中斷狀態位,暫且叫做interruptStatus吧。當前執行sleep()和wait()這些方法的時候,當前線程會把該interrruptStatus狀態位設置為true,以標識當前線程為阻塞狀態。當調用該線程的Interrupt()方法的話,就會重置interruptStatus狀態為為false。而sleep()和wait()方法內部會不斷地輪詢檢查InterruptStatus狀態值,如果某一時刻變為false的時候,當前線程就會中斷阻塞狀態,通過拋出InterrupException的方式來中斷阻塞狀態,然后繼續執行下去。
至於wait()方法和notify()的關系,通過另外一篇文章來講述吧。