程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java多線程間通信-解決安全問題、等待喚醒機制,java多線程

Java多線程間通信-解決安全問題、等待喚醒機制,java多線程

編輯:JAVA綜合教程

Java多線程間通信-解決安全問題、等待喚醒機制,java多線程




/*
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();
        */
    }
}






  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved