徹底明白Java的多執行緒-執行緒間的通訊(2)(轉)
徹底明白Java的多執行緒-執行緒間的通訊(2)(轉)[@more@]2.4 sleep()和yield()的區別
1) sleep()使當前執行緒進入停滯狀態,所以執行sleep()的執行緒在指定的時間內肯定不會執行;yield()只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行。
2) sleep()可使優先順序低的執行緒得到執行的機會,當然也可以讓同優先順序和高優先順序的執行緒有執行的機會;yield()只能使同優先順序的執行緒有執行的機會。
例15:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
//Thread.yield(); (1)
/* (2) */
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
執行結果為:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
由結果可見,透過sleep()可使優先順序較低的執行緒有執行的機會。註釋掉程式碼(2),並去掉程式碼(1)的註釋,結果為:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t2 : 0
t2 : 1
t2 : 2
t2 : 3
可見,呼叫yield(),不同優先順序的執行緒永遠不會得到執行機會。
2.5 join()
使呼叫join()的執行緒執行完畢後才能執行其它執行緒,在一定意義上,它可以實現同步的功能。
例16:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.println(" " + i);
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
try{
t1.join();
}
catch(InterruptedException e){}
t1.start();
}
}
執行結果為:
0
1
2
3
0
1
2
3
3. class Object下常用的執行緒函式
wait()、notify()和notifyAll()這三個函式由java.lang.Object類提供,用於協調多個執行緒對共享資料的存取。
3.1 wait()、notify()和notifyAll()
1) wait()函式有兩種形式:第一種形式接受一個毫秒值,用於在指定時間長度內暫停執行緒,使執行緒進入停滯狀態。第二種形式為不帶引數,代表waite()在notify()或notifyAll()之前會持續停滯。
2) 當對一個物件執行notify()時,會從執行緒等待池中移走該任意一個執行緒,並把它放到鎖標誌等待池中;當對一個物件執行notifyAll()時,會從執行緒等待池中移走所有該物件的所有執行緒,並把它們放到鎖標誌等待池中。
3) 當呼叫wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,從而使執行緒所在物件中的其它synchronized資料可被別的執行緒使用。
例17:
下面,我們將對例11中的例子進行修改
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<10; i++){
shareVar++;
if(shareVar==5){
try{
this.wait(); //(4)
}
catch(InterruptedException e){}
}
}
}
if(shareVar!=0){
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.notify(); //(5)
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(1)
//t1.start(); (2)
t2.start(); //(3)
}
}
執行結果為:
t2 shareVar = 5
因為t1和t2是兩個不同物件,所以執行緒t2呼叫程式碼(5)不能喚起執行緒t1。如果去掉程式碼(2)的註釋,並註釋掉程式碼(3),結果為:
t1 shareVar = 5
t1 shareVar = 10
這是因為,當程式碼(1)的執行緒執行到程式碼(4)時,它進入停滯狀態,並釋放物件的鎖狀態。接著,程式碼(2)的執行緒執行run(),由於此時 shareVar值為5,所以執行列印語句並呼叫程式碼(5)使程式碼(1)的執行緒進入可執行狀態,然後程式碼(2)的執行緒結束。當程式碼(1)的執行緒重新執行後,它接著執行for()迴圈一直到shareVar=10,然後列印shareVar。
3.2 wait()、notify()和synchronized
waite()和notify()因為會對物件的“鎖標誌”進行操作,所以它們必須在synchronized函式或synchronized block中進行呼叫。如果在non-synchronized函式或non-synchronized block中進行呼叫,雖然能編譯透過,但在執行時會發生IllegalMonitorStateException的異常。
例18:
class TestThreadMethod extends Thread{
public int shareVar = 0;
public TestThreadMethod(String name){
super(name);
new Notifier(this);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
System.out.println("i = " + shareVar);
try{
System.out.println("wait......");
this.wait();
}
catch(InterruptedException e){}
}
}
}
}
class Notifier extends Thread{
private TestThreadMethod ttm;
Notifier(TestThreadMethod t){
ttm = t;
start();
}
public void run(){
while(true){
try{
sleep(2000);
}
catch(InterruptedException e){}
/*1 要同步的不是當前物件的做法 */
synchronized(ttm){
System.out.println("notify......");
ttm.notify();
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
}
}
執行結果為:
i = 1
wait......
notify......
i = 2
wait......
notify......
i = 3
wait......
notify......
i = 4
wait......
notify......
i = 5
wait......
notify......
4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的討論
4.1 這兩組函式的區別
1) wait()使當前執行緒進入停滯狀態時,還會釋放當前執行緒所佔有的“鎖標誌”,從而使執行緒物件中的synchronized資源可被物件中別的執行緒使用;而suspend()和sleep()使當前執行緒進入停滯狀態時不會釋放當前執行緒所佔有的“鎖標誌”。
2) 前一組函式必須在synchronized函式或synchronized block中呼叫,否則在執行時會產生錯誤;而後一組函式可以non-synchronized函式和synchronized block中呼叫。
4.2 這兩組函式的取捨
Java2已不建議使用後一組函式。因為在呼叫wait()時不會釋放當前執行緒所取得的“鎖標誌”,這樣很容易造成“死鎖”。
1) sleep()使當前執行緒進入停滯狀態,所以執行sleep()的執行緒在指定的時間內肯定不會執行;yield()只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行。
2) sleep()可使優先順序低的執行緒得到執行的機會,當然也可以讓同優先順序和高優先順序的執行緒有執行的機會;yield()只能使同優先順序的執行緒有執行的機會。
例15:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.print(Thread.currentThread().getName());
System.out.println(" : " + i);
//Thread.yield(); (1)
/* (2) */
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
執行結果為:
t1 : 0
t1 : 1
t2 : 0
t1 : 2
t2 : 1
t1 : 3
t2 : 2
t2 : 3
由結果可見,透過sleep()可使優先順序較低的執行緒有執行的機會。註釋掉程式碼(2),並去掉程式碼(1)的註釋,結果為:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t2 : 0
t2 : 1
t2 : 2
t2 : 3
可見,呼叫yield(),不同優先順序的執行緒永遠不會得到執行機會。
2.5 join()
使呼叫join()的執行緒執行完畢後才能執行其它執行緒,在一定意義上,它可以實現同步的功能。
例16:
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public void run(){
for(int i=0; i<4; i++){
System.out.println(" " + i);
try{
Thread.sleep(3000);
}
catch(InterruptedException e){
System.out.println("Interrupted");
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
try{
t1.join();
}
catch(InterruptedException e){}
t1.start();
}
}
執行結果為:
0
1
2
3
0
1
2
3
3. class Object下常用的執行緒函式
wait()、notify()和notifyAll()這三個函式由java.lang.Object類提供,用於協調多個執行緒對共享資料的存取。
3.1 wait()、notify()和notifyAll()
1) wait()函式有兩種形式:第一種形式接受一個毫秒值,用於在指定時間長度內暫停執行緒,使執行緒進入停滯狀態。第二種形式為不帶引數,代表waite()在notify()或notifyAll()之前會持續停滯。
2) 當對一個物件執行notify()時,會從執行緒等待池中移走該任意一個執行緒,並把它放到鎖標誌等待池中;當對一個物件執行notifyAll()時,會從執行緒等待池中移走所有該物件的所有執行緒,並把它們放到鎖標誌等待池中。
3) 當呼叫wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,從而使執行緒所在物件中的其它synchronized資料可被別的執行緒使用。
例17:
下面,我們將對例11中的例子進行修改
class TestThreadMethod extends Thread{
public static int shareVar = 0;
public TestThreadMethod(String name){
super(name);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<10; i++){
shareVar++;
if(shareVar==5){
try{
this.wait(); //(4)
}
catch(InterruptedException e){}
}
}
}
if(shareVar!=0){
System.out.print(Thread.currentThread().getName());
System.out.println(" shareVar = " + shareVar);
this.notify(); //(5)
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
TestThreadMethod t2 = new TestThreadMethod("t2");
t1.start(); //(1)
//t1.start(); (2)
t2.start(); //(3)
}
}
執行結果為:
t2 shareVar = 5
因為t1和t2是兩個不同物件,所以執行緒t2呼叫程式碼(5)不能喚起執行緒t1。如果去掉程式碼(2)的註釋,並註釋掉程式碼(3),結果為:
t1 shareVar = 5
t1 shareVar = 10
這是因為,當程式碼(1)的執行緒執行到程式碼(4)時,它進入停滯狀態,並釋放物件的鎖狀態。接著,程式碼(2)的執行緒執行run(),由於此時 shareVar值為5,所以執行列印語句並呼叫程式碼(5)使程式碼(1)的執行緒進入可執行狀態,然後程式碼(2)的執行緒結束。當程式碼(1)的執行緒重新執行後,它接著執行for()迴圈一直到shareVar=10,然後列印shareVar。
3.2 wait()、notify()和synchronized
waite()和notify()因為會對物件的“鎖標誌”進行操作,所以它們必須在synchronized函式或synchronized block中進行呼叫。如果在non-synchronized函式或non-synchronized block中進行呼叫,雖然能編譯透過,但在執行時會發生IllegalMonitorStateException的異常。
例18:
class TestThreadMethod extends Thread{
public int shareVar = 0;
public TestThreadMethod(String name){
super(name);
new Notifier(this);
}
public synchronized void run(){
if(shareVar==0){
for(int i=0; i<5; i++){
shareVar++;
System.out.println("i = " + shareVar);
try{
System.out.println("wait......");
this.wait();
}
catch(InterruptedException e){}
}
}
}
}
class Notifier extends Thread{
private TestThreadMethod ttm;
Notifier(TestThreadMethod t){
ttm = t;
start();
}
public void run(){
while(true){
try{
sleep(2000);
}
catch(InterruptedException e){}
/*1 要同步的不是當前物件的做法 */
synchronized(ttm){
System.out.println("notify......");
ttm.notify();
}
}
}
}
public class TestThread{
public static void main(String[] args){
TestThreadMethod t1 = new TestThreadMethod("t1");
t1.start();
}
}
執行結果為:
i = 1
wait......
notify......
i = 2
wait......
notify......
i = 3
wait......
notify......
i = 4
wait......
notify......
i = 5
wait......
notify......
4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的討論
4.1 這兩組函式的區別
1) wait()使當前執行緒進入停滯狀態時,還會釋放當前執行緒所佔有的“鎖標誌”,從而使執行緒物件中的synchronized資源可被物件中別的執行緒使用;而suspend()和sleep()使當前執行緒進入停滯狀態時不會釋放當前執行緒所佔有的“鎖標誌”。
2) 前一組函式必須在synchronized函式或synchronized block中呼叫,否則在執行時會產生錯誤;而後一組函式可以non-synchronized函式和synchronized block中呼叫。
4.2 這兩組函式的取捨
Java2已不建議使用後一組函式。因為在呼叫wait()時不會釋放當前執行緒所取得的“鎖標誌”,這樣很容易造成“死鎖”。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-958351/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 徹底明白Java的多執行緒-執行緒間的通訊(1)(轉)Java執行緒
- java多執行緒5:執行緒間的通訊Java執行緒
- java多執行緒間的通訊Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- Java多執行緒學習——執行緒通訊Java執行緒
- 多執行緒之間通訊及執行緒池執行緒
- 多執行緒之間的通訊執行緒
- 【Java】【多執行緒】兩個執行緒間的通訊、wait、notify、notifyAllJava執行緒AI
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- 執行緒間的通訊執行緒
- 執行緒4--執行緒間通訊執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- java多執行緒:執行緒間通訊——生產者消費者模型Java執行緒模型
- 這麼講執行緒池,徹底明白了!執行緒
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- Android小知識-Java多執行緒相關(執行緒間通訊)上篇AndroidJava執行緒
- Java多執行緒學習(五)執行緒間通訊知識點補充Java執行緒
- Swift多執行緒:使用Thread進行多執行緒間通訊,協調子執行緒任務Swift執行緒thread
- Java執行緒通訊Java執行緒
- 說說Java執行緒間通訊Java執行緒
- Java多執行緒——執行緒Java執行緒
- JAVA - 基於Socket的多執行緒通訊Java執行緒
- Java多執行緒學習(2)執行緒控制Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- Java程式中的多執行緒(2)(轉)Java執行緒
- Java多執行緒——獲取多個執行緒任務執行完的時間Java執行緒
- java 多執行緒-2Java執行緒
- JUC之執行緒間的通訊執行緒
- Java多執行緒/併發11、執行緒同步通訊:notify、waitJava執行緒AI
- Java多執行緒-執行緒中止Java執行緒
- Java多執行緒——執行緒池Java執行緒
- 大話Android多執行緒(三) 執行緒間的通訊機制之HandlerAndroid執行緒
- Java中利用管道實現執行緒間的通訊(轉)Java執行緒
- 【java】【多執行緒】建立執行緒的兩種常用方式(2)Java執行緒
- Java-執行緒間通訊小結Java執行緒
- Java之執行緒通訊Java執行緒
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI