| 導購 | 订阅 | 在线投稿
分享
 
 
 

徹底明白Java的多線程-線程間的通信

來源:互聯網網民  2008-05-31 12:10:43  評論

三. 線程間的通信

1. 線程的幾種狀態

線程有四種狀態,任何一個線程肯定處于這四種狀態中的一種:

1) 産生(New):線程對象已經産生,但尚未被啓動,所以無法執行。如通過new産生了一個線程對象後沒對它調用start()函數之前。

2) 可執行(Runnable):每個支持多線程的系統都有一個排程器,排程器會從線程池中選擇一個線程並啓動它。當一個線程處于可執行狀態時,表示它可能正處于線程池中等待排排程器啓動它;也可能它已正在執行。如執行了一個線程對象的start()方法後,線程就處于可執行狀態,但顯而易見的是此時線程不一定正在執行中。

3) 死亡(Dead):當一個線程正常結束,它便處于死亡狀態。如一個線程的run()函數執行完畢後線程就進入死亡狀態。

4) 停滯(Blocked):當一個線程處于停滯狀態時,系統排程器就會忽略它,不對它進行排程。當處于停滯狀態的線程重新回到可執行狀態時,它有可能重新執行。如通過對一個線程調用wait()函數後,線程就進入停滯狀態,只有當兩次對該線程調用notify或notifyAll後它才能兩次回到可執行狀態。

2. classThread下的常用函數函數

2.1 suspend()、resume()

1) 通過suspend()函數,可使線程進入停滯狀態。通過suspend()使線程進入停滯狀態後,除非收到resume()消息,否則該線程不會變回可執行狀態。

2) 當調用suspend()函數後,線程不會釋放它的「鎖標志」。

例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<5; i++){

shareVar++;

if(shareVar==5){

this.suspend();//(1)

}

}

}

else{

System.out.print(Thread.currentThread().getName());

System.out.println(" shareVar = " + shareVar);

this.resume();//(2)

}

}

}

public class TestThread{

public static void main(String[] args){

TestThreadMethod t1 = new TestThreadMethod("t1");

TestThreadMethod t2 = new TestThreadMethod("t2");

t1.start();//(5)

//t1.start();//(3)

t2.start();//(4)

}

}

運行結果爲:

t2 shareVar = 5

i. 當代碼(5)的t1所産生的線程運行到代碼(1)處時,該線程進入停滯狀態。然後排程器從線程池中喚起代碼(4)的t2所産生的線程,此時shareVar值不爲0,所以執行else中的語句。

ii. 也許你會問,那執行代碼(2)後爲什麽不會使t1進入可執行狀態呢?正如前面所說,t1和t2是兩個不同對象的線程,而代碼(1)和(2)都只對當前對象進行操作,所以t1所産生的線程執行代碼(1)的結果是對象t1的當前線程進入停滯狀態;而t2所産生的線程執行代碼(2)的結果是把對象t2中的所有處于停滯狀態的線程調回到可執行狀態。

iii. 那現在把代碼(4)注釋掉,並去掉代碼(3)的注釋,是不是就能使t1重新回到可執行狀態呢?運行結果是什麽也不輸出。爲什麽會這樣呢?也許你會認爲,當代碼(5)所産生的線程執行到代碼(1)時,它進入停滯狀態;而代碼(3)所産生的線程和代碼(5)所産生的線程是屬于同一個對象的,那麽就當代碼(3)所産生的線程執行到代碼(2)時,就可使代碼(5)所産生的線程執行回到可執行狀態。但是要清楚,suspend()函數只是讓當前線程進入停滯狀態,但並不釋放當前線程所獲得的「鎖標志」。所以當代碼(5)所産生的線程進入停滯狀態時,代碼(3)所産生的線程仍不能啓動,因爲當前對象的「鎖標志」仍被代碼(5)所産生的線程占有。

2.2 sleep()

1) sleep ()函數有一個參數,通過參數可使線程在指定的時間內進入停滯狀態,當指定的時間過後,線程則自動進入可執行狀態。

2) 當調用sleep ()函數後,線程不會釋放它的「鎖標志」。

例12:

class TestThreadMethod extends Thread{

class TestThreadMethod extends Thread{

public static int shareVar = 0;

public TestThreadMethod(String name){

super(name);

}

public synchronized void run(){

for(int i=0; i<3; i++){

System.out.print(Thread.currentThread().getName());

System.out.println(" : " + i);

try{

Thread.sleep(100);//(4)

}

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.start();(1)

t1.start();(2)

//t2.start();(3)

}

}

運行結果爲:

t1 : 0

t1 : 1

t1 : 2

t1 : 0

t1 : 1

t1 : 2

由結果可證實,雖然在run()中執行了sleep(),但是它不會釋放對象的「鎖標志」,所以除非代碼(1)的線程執行完run()函數並釋放對象的「鎖標志」,否則代碼(2)的線程永遠不會執行。

 
特别声明:以上内容(如有图片或视频亦包括在内)为网络用户发布,本站仅提供信息存储服务。
 
  三. 線程間的通信 1. 線程的幾種狀態 線程有四種狀態,任何一個線程肯定處于這四種狀態中的一種: 1) 産生(New):線程對象已經産生,但尚未被啓動,所以無法執行。如通過new産生了一個線程對象後沒對它調用start()函數之前。 2) 可執行(Runnable):每個支持多線程的系統都有一個排程器,排程器會從線程池中選擇一個線程並啓動它。當一個線程處于可執行狀態時,表示它可能正處于線程池中等待排排程器啓動它;也可能它已正在執行。如執行了一個線程對象的start()方法後,線程就處于可執行狀態,但顯而易見的是此時線程不一定正在執行中。 3) 死亡(Dead):當一個線程正常結束,它便處于死亡狀態。如一個線程的run()函數執行完畢後線程就進入死亡狀態。 4) 停滯(Blocked):當一個線程處于停滯狀態時,系統排程器就會忽略它,不對它進行排程。當處于停滯狀態的線程重新回到可執行狀態時,它有可能重新執行。如通過對一個線程調用wait()函數後,線程就進入停滯狀態,只有當兩次對該線程調用notify或notifyAll後它才能兩次回到可執行狀態。 2. class Thread下的常用函數函數 2.1 suspend()、resume() 1) 通過suspend()函數,可使線程進入停滯狀態。通過suspend()使線程進入停滯狀態後,除非收到resume()消息,否則該線程不會變回可執行狀態。 2) 當調用suspend()函數後,線程不會釋放它的「鎖標志」。 例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<5; i++){ shareVar++; if(shareVar==5){ this.suspend(); //(1) } } } else{ System.out.print(Thread.currentThread().getName()); System.out.println(" shareVar = " + shareVar); this.resume(); //(2) } } } public class TestThread{ public static void main(String[] args){ TestThreadMethod t1 = new TestThreadMethod("t1"); TestThreadMethod t2 = new TestThreadMethod("t2"); t1.start(); //(5) //t1.start(); //(3) t2.start(); //(4) } } 運行結果爲: t2 shareVar = 5 i. 當代碼(5)的t1所産生的線程運行到代碼(1)處時,該線程進入停滯狀態。然後排程器從線程池中喚起代碼(4)的t2所産生的線程,此時shareVar值不爲0,所以執行else中的語句。 ii. 也許你會問,那執行代碼(2)後爲什麽不會使t1進入可執行狀態呢?正如前面所說,t1和t2是兩個不同對象的線程,而代碼(1)和(2)都只對當前對象進行操作,所以t1所産生的線程執行代碼(1)的結果是對象t1的當前線程進入停滯狀態;而t2所産生的線程執行代碼(2)的結果是把對象t2中的所有處于停滯狀態的線程調回到可執行狀態。 iii. 那現在把代碼(4)注釋掉,並去掉代碼(3)的注釋,是不是就能使t1重新回到可執行狀態呢?運行結果是什麽也不輸出。爲什麽會這樣呢?也許你會認爲,當代碼(5)所産生的線程執行到代碼(1)時,它進入停滯狀態;而代碼(3)所産生的線程和代碼(5)所産生的線程是屬于同一個對象的,那麽就當代碼(3)所産生的線程執行到代碼(2)時,就可使代碼(5)所産生的線程執行回到可執行狀態。但是要清楚,suspend()函數只是讓當前線程進入停滯狀態,但並不釋放當前線程所獲得的「鎖標志」。所以當代碼(5)所産生的線程進入停滯狀態時,代碼(3)所産生的線程仍不能啓動,因爲當前對象的「鎖標志」仍被代碼(5)所産生的線程占有。 2.2 sleep() 1) sleep ()函數有一個參數,通過參數可使線程在指定的時間內進入停滯狀態,當指定的時間過後,線程則自動進入可執行狀態。 2) 當調用sleep ()函數後,線程不會釋放它的「鎖標志」。 例12: class TestThreadMethod extends Thread{ class TestThreadMethod extends Thread{ public static int shareVar = 0; public TestThreadMethod(String name){ super(name); } public synchronized void run(){ for(int i=0; i<3; i++){ System.out.print(Thread.currentThread().getName()); System.out.println(" : " + i); try{ Thread.sleep(100); //(4) } 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.start(); (1) t1.start(); (2) //t2.start(); (3) } } 運行結果爲: t1 : 0 t1 : 1 t1 : 2 t1 : 0 t1 : 1 t1 : 2 由結果可證實,雖然在run()中執行了sleep(),但是它不會釋放對象的「鎖標志」,所以除非代碼(1)的線程執行完run()函數並釋放對象的「鎖標志」,否則代碼(2)的線程永遠不會執行。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有