多線程間的通訊之等待喚醒機制
阿新 • • 發佈:2017-08-16
run 出了 需求 stat 我們 out man http pre
線程間的通訊:
事實上就是多個線程在操作同一個資源。
可是操作動作不同
樣例:
需求:模擬簡單賣票系統(輸入一個人。緊接著輸出一個人)
class Res { String name; String sex; } class Input implements Runnable { private Res r; private int t=0; Input(Res r) { this.r=r; } public void run() { while(true) { if(t==1) { r.name="nike"; r.sex="man"; } else { r.name="麗麗"; r.sex="女女"; } t=(t+1)%2; } } } class Output implements Runnable { private Res r; Output(Res r) { this.r=r; } public void run() { while(true) { System.out.println("output....."+r.name+"+++"+r.sex); } } } class InputOutputDemo { public static void main(String[] args) { Res r=new Res(); Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); } }
出現了安全問題(輸出了麗麗 MAN)
同步後
class Res { String name; String sex; } class Input implements Runnable { private Res r; private int t=0; Input(Res r) { this.r=r; } public void run() { while(true) { synchronized(Res.class) { if(t==1) { r.name="nike"; r.sex="man"; } else { r.name="麗麗"; r.sex="女女"; } t=(t+1)%2; } } } } class Output implements Runnable { private Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(Res.class) { System.out.println("output....."+r.name+"+++"+r.sex); } } } } class InputOutputDemo2 { public static void main(String[] args) { Res r=new Res(); Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); } }
盡管安全 問題攻克了,但並沒出現我們想要的一男一女交替的情景
這是就引進一種方法:等待喚醒機制
class Res { String name; String sex; boolean flag; } class Input implements Runnable { private Res r; private int t=0; Input(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { if(r.flag) try{r.wait();}catch(Exception e){} if(t==1) { r.name="nike"; r.sex="man"; } else { r.name="麗麗"; r.sex="女女"; } t=(t+1)%2; r.flag=true; r.notify(); } } } } class Output implements Runnable { private Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { if(!r.flag) try{r.wait();}catch(Exception e){} System.out.println("output....."+r.name+"+++"+r.sex); r.flag=false; r.notify(); } } } } class InputOutputDemo3 { public static void main(String[] args) { Res r=new Res(); Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); } }
wait:
notify();
notifyAll();
都使用在同步中,由於要對持有監視器(鎖)的操作。
所以要使用在同步中,由於僅僅有同步才具有鎖。
為什麽這些操作線程的鳳飛飛要定義Object類中呢?
由於這些方法在操作同步中線程時。都必需要標識它們所操作線程中的鎖,
僅僅有同一個鎖上的被等待線程。能夠被同一個鎖上notify喚醒。
不能夠被不同鎖中的線程進行喚醒。
也就是說,等待和喚醒必須是同一個鎖。
而鎖能夠是隨意對象,所以能夠被隨意對象調用的方法定義Object類中。
以下進行代碼改良:
class Res { private String name; private String sex; private boolean flag; public synchronized void set(String name,String sex) { if(this.flag) try{this.wait();}catch(Exception e){} this.name=name; this.sex=sex; this.flag=true; this.notify(); } public synchronized void out() { if(!this.flag) try{this.wait();}catch(Exception e){} System.out.println("output....."+this.name+"+++"+this.sex); this.flag=false; this.notify(); } } class Input implements Runnable { private Res r; private int t=0; Input(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { if(t==1) r.set("nike","man"); else r.set("麗麗","女女女"); t=(t+1)%2; } } } } class Output implements Runnable { private Res r; Output(Res r) { this.r=r; } public void run() { while(true) { synchronized(r) { r.out(); } } } } class InputOutputDemo4 { public static void main(String[] args) { Res r=new Res(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); /* Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); */ } }
多線程間的通訊之等待喚醒機制