yield、sleep、wait、notify、join
Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用
在JAVA中,是沒有類似於PV操作、進程互斥等相關的方法的。JAVA的進程同步是通過synchronized()來實現的,需要說明的是,JAVA的synchronized()方法類似於操作系統概念中的互斥內存塊,在JAVA中的Object類型中,都是帶有一個內存鎖的,在有線程獲取該內存鎖後,其它線程無法訪問該內存,從而實現JAVA中簡單的同步、互斥操作。明白這個原理,就能理解為什麽synchronized(this)與synchronized(static XXX)的區別了,synchronized就是針對內存區塊申請內存鎖,this關鍵字代表類的一個對象,所以其內存鎖是針對相同對象的互斥操作,而static成員屬於類專有,其內存空間為該類所有成員共有,這就導致synchronized()對static成員加鎖,相當於對類加鎖,也就是在該類的所有成員間實現互斥,在同一時間只有一個線程可訪問該類的實例。如果只是簡單的想要實現在JAVA中的線程互斥,明白這些基本就已經夠了。但如果需要在線程間相互喚醒的話就需要借助Object.wait(), Object.nofity()了。
Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說線程在獲取對象鎖後,主動釋放對象鎖,同時本線程休眠。直到有其它線程調用對象的notify()喚醒該線程,才能繼續獲取對象鎖,並繼續執行。相應的notify()就是對對象鎖的喚醒操作。但有一點需要註意的是notify()調用後,並不是馬上就釋放對象鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續執行。這樣就提供了在線程間同步、喚醒的操作。Thread.sleep()與Object.wait()二者都可以暫停當前線程,釋放CPU控制權,主要的區別在於Object.wait()在釋放CPU同時,釋放了對象鎖的控制。
wait()和notify(),notifyAll()是Object類的方法,sleep(),yield(),join()是Thread類的方法。
1、sleep()
使當前線程(即調用該方法的線程)暫停執行一段時間,讓其他線程有機會繼續執行,但它並不釋放對象鎖。
也就是說如果有synchronized同步快,其他線程仍然不能訪問共享數據。註意該方法要捕捉異常。
2、join()
join()方法使調用該方法的線程在此之前執行完畢,也就是等待該方法的線程執行完畢後再往下繼續執行。註意該方法也需
要捕捉異常。
3、yield()
該方法與sleep()類似,只是不能由用戶指定暫停多長時間,並且yield()方法只能讓同優先級的線程有執行的機會。
4、wait()和notify()、notifyAll()
這三個方法用於協調多個線程對共享數據的存取,所以必須在synchronized語句塊內使用。
synchronized關鍵字用於保護共享數據,阻止其他線程對共享數據的存取,但是這樣程序的流程就
很不靈活了,如何才能在當前線程還沒退出
synchronized數據塊時讓其他線程也有機會訪問共享數據呢?此時就用這三個方法來靈活控制。
wait()方法使當前線程暫停執行並釋放對象鎖標示,讓其他線程可以進入synchronized數據塊,當前線程被放入對象
等待池中。當調用notify()方法後,將從對象的等待池中移走一個任意的線程並放到鎖標誌等待池中,只有鎖標誌
等待池中線程能夠獲取鎖標誌;如果鎖標誌等待池中沒有線程,則notify()不起作用。
notifyAll()則從對象等待池中移走所有等待那個對象的線程並放到鎖標誌等待池中。
註意 這三個方法都是java.lang.Object的方法。
sleep(),yield(),join()是Thread類的方法。
所以調用 這幾個方法的時候,如果繼承了 thread 類,則可以直接調用,否則要用 Thread.currentThread()獲取當前線程。、
或者 使用 Thread.方法名()
典型案例(暫時也想不出其他案例 = =!),在main 方法中調用 sleep()。
main 方法所在類沒有 繼承 thread 類時,不能直接使用 sleep(), 需要寫成:
Thread.currentThread().sleep(200); 或 Thread.sleep(200);
當 main方法所在類繼承 thread 後,就可以直接寫成: sleep(200);
yeild() 和 sleep()
sleep() 方法使當前運行中的線程睡眠一段時間,進入不可以運行狀態,這段時間的長短是由程序設定的,yield方法使當
前線程讓出CPU占有權,但讓出的時間是不可設定的。
yield()也不會釋放鎖標誌。
實際上,yield()方法對應了如下操作;先檢測當前是否有相同優先級的線程處於同可運行狀態,如有,則把CPU的
占有權交給次線程,否則繼續運行原來的線程,所以yield()方法稱為“退讓”,它把運行機會讓給了其他線程。
yield()只是使當前線程重新回到可執行狀態,所有執行yield()的線程有可能在進入到可執行狀態後馬上又被執行,
yield、sleep、wait、notify、join