javase學習記錄之------生成者消費者之等待喚醒機制

絕代風華.發表於2020-10-24
package src;

/*
分析:
    資源類:Student
    設定學生資料:SetThread(生產者)
    獲取學生資料:GetThread(消費者)
    測試類:StudentDemo

問題1:按照思路寫程式碼,發現資料每次都是null---0
原因:我們在每個執行緒中都建立了新的資源(新的學生類物件),而我們的要求是獲取執行緒的資源應該是同一個
如何實現呢?
    通過外界把這個資料建立出來,通過構造方法傳遞給其他類。

問題2:為了資料的效果更好一些,我加入了迴圈和判斷,給了不同的值,這個時候產生了新的問題
1:同一個資料出現多次
2:姓名和年齡不匹配
原因:
    1:同一個資料出現多次
        SetThread搶到一次,此時是林青霞27,然後就一直是GetThread搶到,所以就一直輸出這個
        CPU的一點點時間片的執行權,就足夠執行很多次
    2:姓名和年齡不匹配
        SetThread搶到執行權,此時X=1,走到 s.setName("周志武");然後就被別人搶了執行權,但是年齡還沒來得及改,所以就變成了周志武27
        如果是個整體就不會出現這種情況了
        總的來說就是執行緒執行的隨機性導致的

執行緒安全問題:
    1:是否是多執行緒環境 是
    2:是否又共享資料 是
    3:是否又多條語句共享資料 是       符合產生問題的條件

解決方案:
    加鎖!
    注意:
    1:不同種類的執行緒都要加鎖
    2:不同種類的執行緒加的鎖必須是同一把,都在裡面用Objict obj 就是new了兩把鎖,是不行的,就用我們外面的s就ok的。

問題3:雖然資料安全了,但是呢,一次一大片不好看,我就想依次的一次一個輸出
如何實現呢?
     通過Java提供的等待換線機制解決
等待喚醒:
    Object類中提供了3個方法:
        wait():等待
        notify():喚醒單個執行緒
        notifyAll():喚醒所以執行緒
    為什麼這些方法不定義在Thread類中呢?
        這些方法的呼叫必須通過鎖物件呼叫,而外面房產使用的鎖物件是任意鎖物件,所以,這些方法必須定義在Object類中

 */
public class StudentDemo {
    public static void main(String[] args) {
        //建立資源
        Student s=new Student();

        SetThread st=new SetThread(s);
        GetThread gt=new GetThread(s);

        Thread t1=new Thread(st);
        Thread t2=new Thread(gt);

        t1.start();
        t2.start();

    }
}
package src;

public class Student {
    private String name;
    private int age;
    boolean flag;//預設情況下是沒有資料,如果true,就說明有資料

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

package src;

public class SetThread implements Runnable {
    private  Student s;
    private int x=0;

    public SetThread(Student s ){
        this.s=s;
    }
    @Override
    public void run() {
        while (true){
            synchronized (s) {
                //判斷有沒有
                if(s.flag){
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }//剛開始flag是flase,就不往if裡面走,然後開始生產
                if (x % 2 == 0) {
                    s.setName("林青霞");
                    s.setAge(27);
                } else {
                    s.setName("周志武");
                    s.setAge(18);
                }
                x++;
                //修改標記
                s.flag=true;
                //喚醒執行緒
                s.notify();
                //一路走下來,如果有就修改標記,並喚醒執行緒
                //喚醒t2,喚醒並不代表你馬上可以走,你還得搶cpu的執行權
                //如何此時t1搶到了,進入if,開始wait方法,然後t2搶到,接著執行
                //t2搶到,皆大歡喜。
            }
        }
//    @Override
//    public void run() {
//        while (true){
//            if(x%2==0) {
//                s.setName("林青霞");
//                s.setAge(27);
//            }else {
//                s.setName("周志武");
//                s.setAge(18);
//            }
//            x++;
//        }
    }
}

package src;

public class GetThread implements Runnable {
    private  Student s;
    public GetThread(Student s ){
        this.s=s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if(!s.flag){
                    try {
                        s.wait();//真就等待,並釋放鎖(wait方法可以釋放),將來醒過來的時候,也是從這裡醒過來。
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(s.getName() + "---" + s.getAge());
                //修改標記
                s.flag=false;
                //喚醒執行緒
                s.notify();
            }
        }
    }
//    @Override
//    public void run() {
//        while (true) {
//            System.out.println(s.getName() + "---" + s.getAge());
//        }
//    }
}

-18
林青霞—27
周志武—18
林青霞—27
周志武—18
林青霞—27
周志武—18
林青霞—27
周志武—18
林青霞—27
周志武—18
。。。

相關文章