/*
1.增加一個知識點
一個類怎麼在所有的類中,讓其它類來共同修改它的數據呢?
可以用單例設計模式
可以用靜態
可以在其它類中做一個構造函數,接受同一個對象,這樣就可以實現對象
2.狀態選擇
可以用數字0 1 判斷
可以用bool
注意變量的范圍即可
3.加了同步後,還是有安全怎麼辦?
想前提! 1. 兩個及以上線程(同步的) 2.操作公用資源 3.要用同一鎖
*/
/*
線程間通訊:
其實就是多個線程在操作同一個資源,
但是操作的動作不同。
*/
/*
1.為什麼會出現安全問題?
就是不滿足前提呗
2.我們還沒有了解到線程的本質
1.線程的執行時互相爭搶執行權的
2.如果沒有同步代碼塊的話,就會對數據進行胡亂修改,有可能修改到一半,另一個線程進來,有可能修改好幾次,等等,甚至還會無視條件
3.即便有了同步代碼塊,也不能保證代碼是按次序相互執行,因為,第一個線程執行完之後,還會參與下一次的爭搶當中來,擁有相同的爭搶概率
所以就出現同步中的不同步狀況,這時候就要用到喚醒
4.其實程序就是一個邏輯判斷問題,就是看有沒有數據
*/
/*五種狀態之一的等待
1.是Thread從上帝那裡繼承來的
2.而且這個函數是拋了異常的,根據異常的格式,要try和catch
3.喚醒也是繼承上帝的
4.使用的時候,直接用對象點出來就可以
5.這樣很容易區分,也造成為什麼要把這兩個函數寫在上帝裡面的原因,鎖是任意類型的,什麼對象都可以
*/
class Res /*定義一個類,裡面封裝好數據成員,用來去調用*/
{
String name;
String sex;
boolean flag = false; /*用來判斷是否已經存入數據,封裝好用來調用*/
}
class Input implements Runnable
{
private Res r ;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r) /*只能讓一個線程進來,而且輸入的先進來,輸出的就不給進了,這樣就滿足了前提,有兩個線程,同一鎖,公共資源*/
{
if(r.flag) /*真,凍結*/
try{r.wait();}catch(Exception e){} /*線程池,等待線程都在線程池當中,喚醒的是什麼,喚醒的都是線程池當中的線程*/
if(x==0)
{
r.name="mike"; /*賦值*/
r.sex="man";
}
else
{
r.name="麗麗";
r.sex = "女女女女女";
}
x = (x+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(r.name+"...."+r.sex); /*刪除*/
r.flag = false;
r.notify(); /*喚醒輸入線程*/
}
}
}
}
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(); /*開啟線程,調用run函數*/
t2.start();
}
}
//notifyAll();
/*
wait:
notify();
notifyAll();
都使用在同步中,因為要對持有監視器(鎖)的線程操作。
所以要使用在同步中,因為只有同步才具有鎖。
為什麼這些操作線程的方法要定義Object類中呢?
因為這些方法在操作同步中線程時,都必須要標識它們所操作線程只有的鎖,
只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒。
不可以對不同鎖中的線程進行喚醒。
也就是說,等待和喚醒必須是同一個鎖。
而鎖可以是任意對象,所以可以被任意對象調用的方法定義Object類中。
*/
代碼優化:
/*
線程間通訊:
其實就是多個線程在操作同一個資源,
但是操作的動作不同。
*/
class Res
{
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name,String sex)
{
if(flag)
try{this.wait();}catch(Exception e){} /*記住,加同步的是共同操作的數據,不是定義數據,是會變動的數據*/
this.name = name;
this.sex = sex;
flag = true;
this.notify(); /*this代表同步函數的鎖,也代表當前對象*/
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(Exception e){}
System.out.println(name+"........"+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable
{
private Res r ; /*用來接收同一個對象*/
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if(x==0)
r.set("mike","man"); /*這個函數已經是同步函數了*/
else
r.set("麗麗","女女女女女");
x = (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res r ;
Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out(); /*不斷輸出*/
}
}
}
class InputOutputDemo2
{
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();
*/
}
}