1. 程式人生 > >Java多執行緒生產者與消費者等待喚醒機制(示例)

Java多執行緒生產者與消費者等待喚醒機制(示例)

在下面新建的兩條執行緒,兩條執行緒操作的物件都是學生類,一條執行緒生產學生物件的資料,一條執行緒消費學生物件的資料,且做到,有資料才消費,沒資料就等待,沒資料就生產,有資料就等待。

第一個案例是學生類物件,非常的簡單就定義了兩個成員變數,以及一個用於喚醒執行緒的標記。

成員變數預設會賦值,生命週期隨著物件的產生而產生,隨著物件的銷燬而銷燬,成員變數儲存在堆中

靜態變數就是類變數,隨著類的產生而產生,隨著類的銷燬而銷燬

區域性變數,方法體,或引數,隨著方法產生或銷燬,分配在棧記憶體中

​public class Student {
    public String name;
    public int age;
    boolean flag; //預設情況是false--->沒有資料,如果是true說明有資料。
}
​

下面的是生產者學生物件的demo

在構造方法中傳遞了學生物件,保證生產者與消費者操作的是同一個物件。

wait:釋放資源,釋放鎖,object的方法,用在同步鎖中,以鎖控制執行緒

wait(),notify(),notifyAll()方法是用在同步當中的:必須是同步當中的同一把鎖操作執行緒。

package secondDemo;

/**
 * Created by df on 2018/8/16.
 */
public class setThread implements Runnable {
    private Student s;
    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為false 執行以下程式碼
                if (x % 2 == 0) {
                    s.name = "java";
                    s.age = 25;
                } else {
                    s.name = "android";
                    s.age = 20;
                }
                x++;
                //資料生產一次  修改標記為true,有了資料生產資料的執行緒就等待
                s.flag=true;
                //喚醒執行緒
                s.notify();
            }
        }
    }
}

下面的是學生物件的消費者模式demo

 在構造方法中傳遞了學生物件,保證生產者與消費者操作的是同一個物件。

package secondDemo;

/**
 * Created by df on 2018/8/16.
 */
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();//在等待的時候立即釋放鎖,方便其他的執行緒使用鎖。而且被喚醒時,就在此處喚醒,
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // flag--->true:消費資料
                System.out.println(s.name + "  ====   " + s.age);
                // 消費完畢後,資料沒有了,修改標記
                s.flag = false;
                // 喚醒執行緒
                //喚醒並不代表你立即可以得到執行權,此時仍然需要搶CPU的執行權,
                s.notify();
            }
        }
    }
}

下面的是測試用例,就是簡單的建立了兩條執行緒,然後啟動剛才的生產者與消費者

  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();

    }

最後就是執行完畢的結果