在說生產者消費者模式之前,我覺得有必要理解一下 Obj.wait(),與Obj.notify()方法。wait()方法是指在持有對象鎖的線程調用此方法時,會釋放對象鎖,同時休眠本線程。notify()方法是持有相同的對象鎖來喚醒休眠的線程,使其具有搶占cpu的資格。可以理解同步方法,同步方法的對象鎖就是誰調用這個方法,這個對象就是對象鎖。
根據李興華老師的視頻講解,建立一個生產者類,一個消費者類,還有一個Info類,貼上代碼:
1.生產者類
package com.company; /** * Created by Administrator on 2016/8/30. */ public class Productor implements Runnable { private Info info; public Productor(Info info) { this.info = info; } @Override public void run() { for (int i=0;i<50;i++) { if (i%2==0) { // info.setTitle("陶帥"); // info.setContent("一個帥哥"); // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } info.set("陶帥","一個帥哥"); }else { // info.setTitle("可愛的動物"); // info.setContent("草泥馬"); info.set("可愛的動物","草泥馬"); // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } } } } }
2.消費者類
package com.company; /** * Created by Administrator on 2016/8/30. */ public class Consumer implements Runnable { private Info info; public Consumer(Info info) { this.info = info; } @Override public void run() { for (int i=0;i<50;i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } info.get(); } } }
3.Info類(重點)
package com.company; /** * Created by Administrator on 2016/8/30. */ public class Info { private String Title; private String content; private boolean flag=true;//true表示可以生產不能取走消費,false相反 public synchronized void set(String Titile,String content){ if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.Title=Titile; this.content=content; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } flag=false; notify(); } public synchronized void get(){ if (flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.Title+"------->"+this.content); flag=true; notify(); } // public String getTitle() { // return Title; // } // // public void setTitle(String title) { // Title = title; // } // // public String getContent() { // return content; // } // // public void setContent(String content) { // this.content = content; // } }
4.測試類
package com.company; public class Main { public static void main(String[] args) { Info info=new Info(); Productor p=new Productor(info); Consumer c=new Consumer(info); new Thread(p).start(); new Thread(c).start(); } }
總結分析:生產者和消費者兩個線程同時搶占CPU,假如消費者先搶到,此時調用get()方法即消費取走,但是此時flag為true,因此會進入wait()方法,所以此時只能是生產者搶占到CPU,根據生產者調用set()方法,生產后執行
flag=false; notify();
此時生產者和消費者所在的兩個線程又站在同一起跑線上了,繼續CPU爭奪戰。如果不幸的消費者又沒有搶過生產者,生產者繼續執行set();此時flag已經是false了,根據代碼
if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
所以生產者只能乖乖的wait();CPU回到消費者這里,循環往復,模式就出來了,完美!