Java——設定執行緒等待與執行緒喚醒
阿新 • • 發佈:2018-12-31
//執行緒間的通訊:執行緒的任務不同,但是執行緒操作的資料相同
/*
wait(),notify(),notifyAll()必須用在同步中,因為同步中才有鎖
指明讓持有哪個鎖的執行緒去等待或被喚醒
*/
//還是上次的例子,實現存一個輸出一個,而不是輸出一大堆
//描述資料
class Res{
String name;
String sex;
//加一個flag標記,false表示沒有資料
//false即可以存,存完之後,flag改為true,喚醒輸出執行緒,然後放棄CPU,讓他等待
//等輸出資料的任務輸出一組資料後,把輸入的執行緒喚醒,把flag改為false,
//然後放棄CPU,即讓其也進入等待狀態,再讓輸入執行緒接著存
boolean flag = false;
}
//利用建構函式,把同一個res傳給輸入任務和輸出任務
//即保證了兩者為同一個res
//描述輸入任務
class Input implements Runnable{
private Res res;
//兩個執行緒同一把鎖才能實現互相排斥,所以不用obj鎖,用res當鎖
//private Object obj = new Object();
public Input(Res res){
this.res = res;
}
public void run(){
int i = 1 ;
while(true){
//下面的if條件語句和else中的語句存在安全問題
//因為是兩句話,中間有可能被其他執行緒搶走CPU
//所以在輸出的時候會有“張三....女”這樣的輸出
//解決四路:存資料的時候不能輸出
//方法,對t1和t2兩個執行緒進行同步操作,但是要保證用
//同一把鎖,所以不能再用obj鎖
/*if(i==1){
res.name = "張三";
res.sex = "男";
}else{
res.name = "李四";
res.sex = "女";
}*/
synchronized(res){
//先判斷該不該存
//如果flag是true,說明有資料,不能輸入,讓其等待
//wait()方法必須用在同步當中,因為同步當中才有鎖
if(res.flag){
//wait前加res的原因,因為有可能有其他執行緒,其他鎖
//通過鎖來執行,讓哪個執行緒來等待
//等待的執行緒會放棄鎖
try{res.wait();}catch(InterruptedException e){e.printStackTrace();}
}
//如果是false,輸入資料
if(i==1){
res.name = "張三";
res.sex = "男";
}else{
res.name = "李四";
res.sex = "女";
}
//輸入完成後將flag標誌改為true,意思是可以輸出了
res.flag = true;
res.notify();//喚醒輸出執行緒,允許空喚醒,即沒有需要被喚醒的也可以
}
//1 0切換
i = (i+1)%2;
}
}
}
//描述輸出任務
class Output implements Runnable{
private Res res;
public Output(Res res){
this.res = res;
}
public void run(){
while(true){
synchronized(res){
//判斷該不該輸出
//如果flag是false,則沒有資料可以輸出,讓其等待
if(!res.flag){
try{res.wait();}catch(InterruptedException e){e.printStackTrace();}
}
System.out.println(res.name+"...."+res.sex);
//把flag改為false,意思是可以進行輸入了
res.flag = false;
//喚醒輸入程序
res.notify();
}
}
}
}
class test{
public static void main(String[] args){
//建立資源物件
Res res = new Res();
//輸入任務和輸出任務用同一個物件,即相同的資源
//建立輸入任務
Input in = new Input(res);
//建立輸出任務
Output out = new Output(res);
//建立輸入執行緒
Thread t1 = new Thread(in);
//建立輸出執行緒
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}