2019獨角獸企業重金招聘Python工程師標準>>>
1.何為生產者與消費者
????在線程世界里,生產者就是生產數據的線程,消費者就是消費數據的線程。
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;/*** @ClassName:Restraurant* @Description:何為生產者與消費者* @author: * @date:2018年5月3日*/
public class Restraurant {Meal m=null;Chef chef=new Chef(this);WaitPerson wait=new WaitPerson(this);ExecutorService service=Executors.newCachedThreadPool();public Restraurant() {service.execute(chef);service.execute(wait);}public static void main(String[] args) {new Restraurant();}
}
/*** @ClassName:Meal* @Description:生產者生成的數據* @author: * @date:2018年5月3日*/
class Meal{private final int orderNum;//食物訂單編號public Meal(int num){orderNum=num;}public String toString(){return "Meal"+orderNum;}
}
/*** @ClassName:Chef* @Description:廚師類,及生產者* @author: * @date:2018年5月3日*/
class Chef implements Runnable{Restraurant r;int count=0;public Chef(Restraurant r) {this.r=r;}@Overridepublic void run() {try{while(!Thread.interrupted()){synchronized (this) {while(r.m!=null){System.out.println("廚師等待中");wait();//等待服務員取餐}}if(count++==10){System.out.println("今日已售完");r.service.shutdownNow();}System.out.println("訂單完成,服務員取餐");synchronized (r.wait) {r.m=new Meal(count);r.wait.notifyAll();}TimeUnit.SECONDS.sleep(1);}}catch (InterruptedException e) {System.out.println("生產者線程強制中斷");}}
}
/*** @ClassName:WaitPerson* @Description:服務員類,即消費者* @author: * @date:2018年5月3日*/
class WaitPerson implements Runnable{Restraurant r;public WaitPerson(Restraurant r) {this.r=r;}@Overridepublic void run() {try {while (!Thread.interrupted()) {synchronized (this) {while (r.m == null) {System.out.println("服務員等待中");wait();// 等待廚師生成食物}}System.out.println("服務員以取餐" + r.m);synchronized (r.chef) {r.m = null;r.chef.notifyAll();}}} catch (InterruptedException e) {System.out.println("消費者線程強制中斷");}}}
2.生產者與消費者模式
? ? 1)產生原因:在多線程開發 中,如果生產者處理速度很快,而消費者處理速度很慢,那么生產者就必須等待消費者處理 完,才能繼續生產數據。同樣的道理,如果消費者的處理能力大于生產者,那么消費者就必須 等待生產者。wait與notify方法以一種非常低級的方式解決了任務互相通知的問題,即每次交互都要進行一次握手,極大影響的效率以及性能,為了解決這種生產消費能力不均衡的問題,便有了生產者和消費者模式。
? ? 2)原理:生產者和消費者模式是通過一個容器(比如同步阻塞隊列)來解決生產者和消費者的強耦合問題。生產者和消 費者彼此之間不直接通信,而是通過阻塞隊列來進行通信,所以生產者生產完數據之后不用 等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列里取, 阻塞隊列就相當于一個緩沖區,平衡了生產者和消費者的處理能力。 這個阻塞隊列就是用來給生產者和消費者解耦的。java.util.concurrent.BlockingQueue接口提供了這個隊列,通常使用其實現子類ArrayBlockingQueue,LinkedBlockingQueue。當消費者任務試圖從同步隊列中獲取對象,如果隊列為空時,那么隊列則會掛起消費者任務,并且當擁有足夠多的元素可用時才會恢復消費者任務。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;public class UseBlockingQueue {public static void main(String[] args) throws InterruptedException {LinkedBlockingQueue<Toast> dry=new LinkedBlockingQueue<Toast>(),butter=new LinkedBlockingQueue<Toast>(),jam=new LinkedBlockingQueue<Toast>(),con=new LinkedBlockingQueue<Toast>();ExecutorService exec=Executors.newCachedThreadPool();exec.execute(new MakeToast(dry));//制作初始吐司任務exec.execute(new Butter(dry,butter));//吐司抹黃油任務exec.execute(new Jam(butter,jam));//吐司抹果醬任務exec.execute(new Consumer(jam));//消費者任務,食用吐司TimeUnit.SECONDS.sleep(5);exec.shutdownNow();}
}
class Toast{private int status;//吐司狀態:0代表制作吐司,1代表抹黃油,2代表向抹了黃油的吐司抹果醬private final int id;public Toast(int id1) {id=id1;}public void butter(){status=1;};public void jam(){status=2;}public int getStatus(){return status;}public int getId(){return id;}public String toString(){return "toast "+id+":"+status;}
}
/*** @Description:制作初始吐司*/
class MakeToast implements Runnable{private LinkedBlockingQueue<Toast> queue=new LinkedBlockingQueue<Toast>();private int count=0;public MakeToast(LinkedBlockingQueue<Toast> q) {queue=q;}@Overridepublic void run() {try{while(!Thread.interrupted()){Thread.sleep(1000);//制作時間Toast t=new Toast(count);System.out.println(t);queue.put(t);//添加到同步隊列count++;}}catch (InterruptedException e) {System.out.println("make process interrupted");}System.out.println("make process off");}
}
/*** @Description:涂抹黃油*/
class Butter implements Runnable{private LinkedBlockingQueue<Toast> queue1,queue2;//未加料吐司隊列,抹黃油后吐司隊列public Butter(LinkedBlockingQueue<Toast> q1,LinkedBlockingQueue<Toast>q2) {queue1=q1;queue2=q2;}@Overridepublic void run() {try{while(!Thread.interrupted()){Toast t=queue1.take();//如果隊列中沒有可用元素將會阻塞,直至有可用元素被添加t.butter();System.out.println(t);queue2.put(t);}}catch (InterruptedException e) {System.out.println("butter process interrupted");}System.out.println("butter process off");}
}
/*** @Description:涂抹果醬*/
class Jam implements Runnable{private LinkedBlockingQueue<Toast> queue1,queue2;//抹黃油后吐司隊列,抹果醬吐司隊列public Jam(LinkedBlockingQueue<Toast> q1,LinkedBlockingQueue<Toast>q2) {queue1=q1;queue2=q2;}@Overridepublic void run() {try{while(!Thread.interrupted()){Toast t=queue1.take();//如果隊列中沒有可用元素將會阻塞,直至有可用元素被添加t.jam();System.out.println(t);queue2.put(t);}}catch (InterruptedException e) {System.out.println("jam process interrupted");}System.out.println("jam process off");}
}
/*** @Description:被食用*/
class Consumer implements Runnable{private LinkedBlockingQueue<Toast> finished;//抹黃油后吐司隊列,抹果醬吐司隊列int count=0;public Consumer(LinkedBlockingQueue<Toast> q) {finished=q;}@Overridepublic void run() {try{while(!Thread.interrupted()){Toast t=finished.take();//如果隊列中沒有可用元素將會阻塞,直至有可用元素被添加if(t.getId()!=count++||t.getStatus()!=2){System.out.println("過程出現錯誤");return;}else{System.out.println("所有過程正確實現"+"toast "+t.getId()+"被食用");}}}catch (InterruptedException e) {System.out.println("eat process interrupted");}System.out.println("eat process off");}
}
?