1. 程式人生 > >生產者和消費者之等待喚醒機制

生產者和消費者之等待喚醒機制

package test48;

/***
 * 多執行緒:生產者消費者問題程式碼
 * 
 * 分析: 資源類:Student 
 * 設定學生資料:SetThread(生產者) 
 * 獲取學生資料:GetThread(消費者) 
 * 測試類:StudentDemo
 * 
 * 問題:發現數據每次都是:null---0 
 * 原因:在每個執行緒中都建立了新的資源,而我們要求的時候設定和獲取執行緒的資源應該是同一個
 * 如何解決:在外界把這個資料創建出來,通過構造方法傳遞給其他的類。
 * 
 * 問題:為了資料的效果好些,就加入了迴圈和判斷,給出不同的值,這個時候產生新問題 
 * A:同一個資料出現多次B:姓名和年齡不匹配
 * 
 * 原因: A:同一個資料出現多次 
 * CPU的一點點時間片的執行權,就足夠你執行很多次。
 *  B:姓名和年齡不匹配 
 *  執行緒執行的隨機性 
 *  
 *  執行緒安全問題:
 * 是否是多執行緒環境 是 
 * 是否有共享資料 有
 *  是否有多條語句操作 有
 *  
 *   解決方案:加鎖
 *   A:不同種類的執行緒都要加鎖
 *   B:不同種類的執行緒加的鎖必須是同一把。
 *   
 *   
 *   等待喚醒:
 *          Object類中提供了三個方法:
 *              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(); } } // 資源類 class Student { String name; int age; boolean flag;//預設是flase,是沒有資料。如果是true,代表有資料。 } class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override
public void run() { // TODO Auto-generated method stub while (true) { synchronized (s) { //判斷有沒有資料 if(s.flag) { try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (x % 2 == 0) { s.name = "白"; s.age = 32; } else { s.name = "小黑"; s.age = 90; } x++; //有就修改標記,並喚醒 s.flag=true; s.notify(); } } } } class GetThread implements Runnable { private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { // TODO Auto-generated method stub while (true) { synchronized (s) { if(!s.flag) { try { s.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(s.name + "---" + s.age); //有就消費,然後修改標記,並喚醒執行緒 s.flag=false; s.notify(); } } } }