1. 程式人生 > >Java多執行緒wait與synchronized方法

Java多執行緒wait與synchronized方法

兩種wait()方法

第一種需要一個以毫秒計的時間作引數,它的意思和sleep()一樣,都是:“暫停一段時間”區別在於:

1.wait()會釋放物件的鎖,也就是說線上程wait()期間,別的執行緒可以呼叫它的synchronized方法。

  執行緒sleep()的時候,不會釋放物件的鎖。當對wait中的執行緒呼叫interrupt時,會先重新獲取物件的鎖,再丟擲InterruptedException。獲取物件鎖定之前,並無法丟擲InterruptedException異常。

2.除了時間到,wait()還可以用notify()或notifyAll()中止.

第二種wait()不需要任何引數,它的用途更廣.執行緒呼叫了這種wait()之後,會一直等下去,直到有別的執行緒呼叫了這個物件notify()或notifyAll().

wait()方法的使用

使用wait()方法時,執行緒便進入wait set,假設現在已經執行一個如下的語句:

obj.wait();

則目前的執行緒會暫時停止執行,進入例項obj的wait set。這個操作稱為:執行緒在obj上wait。

如果例項方法含有如下的語句時:

wait();

則其意義同:

this.wait();

故執行wait()的執行緒就會進入this的wait set。此時,就變成了執行緒在this上wait。

和sleep()屬於Thread類的方法不同,wait()、notify()和notifyAll()是根object的方法。雖然這種做法(把專為多執行緒服務的方法放到通用的根類裡面)看上去有些奇怪,但卻是必要的。因為它們所操控的是每個物件都會有的鎖。

所以結論就是,你只能在synchronized方法或synchronized段裡呼叫wait(),notify(),notifyAll(),否則程式執行時會丟擲IllegalMonitorStateException。這個異常帶著一個挺讓人費解的“current thread not owner”訊息。這個訊息的意思是,如果執行緒呼叫物件的wait(),notify(),notifyAll(),必須先擁有這個物件的鎖。

呼叫notify()、notifyAll()方法後,被喚醒的唯一一個執行緒執行的第一條語句,是緊跟在wait()方法後面的語句。

synchronized方法

synchronized void f() { }

synchronized void g(){ }

每個物件都有一個鎖(也稱監控器monitor),它是物件生來就有的東西(因此你不必為此寫任何程式碼)。當你呼叫synchronized方法時,這個物件就被鎖住了。在方法返回並且解鎖之前,誰也不能呼叫同一個物件的其它synchronized方法。

執行緒在執行同步方法時是具有排它性的。當任意一個執行緒進入到一個物件的任意一個同步方法時,這個物件的所有同步方法都被鎖定了,在此期間,其他任何執行緒都不能訪問這個物件的任意一個同步方法,直到這個執行緒執行完它所呼叫的同步方法並從中退出,從而導致它釋放了該物件的同步鎖之後。在一個物件被某個執行緒鎖定之後,其他執行緒是可以訪問這個物件的所有非同步方法的。

如果你呼叫了f( ),那麼在f( )返回並且解鎖之前,你是不能呼叫同一個物件的g( )的只要有例項就會相對有一個鎖定,不是說因為某個例項的synchronized方法正在執行中,導致無法執行其他例項的synchronized方法。

synchronized方法和synchronized塊,無論碰到return或是異常,都會解除鎖定。

要呼叫synchronized例項方法的執行緒,一定要先獲取this的鎖定。一個例項的鎖定,同一時間內只能有一個執行緒可以得到。

如果例項不同,那鎖定也不同了。如果有多個相異例項,那多個執行緒仍然可以分別執行不同例項的synchronized方法。

使用synchronized塊的時候,特別需要考慮“獲取誰的鎖定來保護”的情況。因為synchronized塊需要明確的指出要獲取的是哪個物件的鎖定。例如:

synchronized (obj){

………….

}