package com.wkcto.chapter07.producerconsumer.p3;
/**
* 生產者消費者設計模式
* 在企業中有一組工人負責生產, 有一組員工負責銷售, 他們都可以同時進行工作
* 工人生產的產品存儲到倉庫中, 如果倉庫已滿, 需要等待銷售人員銷售后,再繼續生產
* 銷售人員從倉庫中銷售產品, 如果倉庫已空, 需要等待生產者生產了產品后再繼續銷售
* 工人在生產產品期間, 還沒有完全生產完, 不能銷售
* 產品在銷售過程中, 也不能再存儲到倉庫中
*
* 定義線程模擬不同的生產 者, 定義線程模擬不同的消費者, 不管是生產者還是消費者都需要借助倉庫中轉
*
* @author 蛙課網
*
*/
public class Test01 {
public static void main(String[] args) {
//創建倉庫對象
MyStorage storage = new MyStorage();
//創建三個生產者
Producer lisi = new Producer(storage);
Producer feifei = new Producer(storage);
Producer xiaoming = new Producer(storage);
lisi.setName("lisi");
feifei.setName("feifei");
xiaoming.setName("xiaoming");
lisi.start();
feifei.start();
xiaoming.start();
//創建三個消費者
Consumer yong = new Consumer(storage);
Consumer zhang = new Consumer(storage);
Consumer du = new Consumer(storage);
yong.setName("yong");;
zhang.setName("zhang");
du.setName("du");
yong.start();
zhang.start();
du.start();
}
}
package com.wkcto.chapter07.producerconsumer.p3;
/**
* 倉庫類
* @author 蛙課網
*
*/
import java.util.LinkedList;
public class MyStorage {
private LinkedList<String> list = new LinkedList<>(); //作為倉庫,保存產品
private static final int MAX = 100; //定義常量,表示倉庫的最大容量
//向倉庫中存儲產品 , 在存儲產品期間不允許消費
public synchronized void store( String product) {
//如果倉庫已滿 , 需要等待消費者消費
while ( list.size() >= MAX) {
try {
this.wait(); //wait()/nofity()方法必須在同步代碼塊中,由鎖對象調用
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//存儲產品
list.offer(product);
System.out.println("++++++++++++++" + Thread.currentThread().getName() + "存儲了" + product + "后,倉庫容量:" + list.size());
//通知消費者消費
this.notify();
}
//從倉庫中取產品 , 生產者需要等消費者取完產品后才能再存儲產品
public synchronized void get() {
//如果倉庫已空, 消費者需要等待
while ( list.size() <= 0 ) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取產品
System.out.println( Thread.currentThread().getName() + "取了產品" + list.poll()+ "后,倉庫容量:" + list.size());
//通知生產者生產
this.notifyAll();
}
}
package com.wkcto.chapter07.producerconsumer.p3;
import java.util.Random;
/**
* 定義生產者線程
* 生產了產品存儲到倉庫中
* @author 蛙課網
*
*/
public class Producer extends Thread {
MyStorage storate; //倉庫
public Producer(MyStorage storate) {
super();
this.storate = storate;
}
@Override
public void run() {
//不斷生產產品
for( int i = 1; i <= 100; i++){
String product = "product:" + new Random().nextInt(200);
storate.store( product );
}
}
}
package com.wkcto.chapter07.producerconsumer.p3;
/**
* 定義消費者線程
* 消費者從倉庫中取產品
* @author 蛙課網
*
*/
public class Consumer extends Thread {
MyStorage storate; //倉庫
public Consumer(MyStorage storate) {
super();
this.storate = storate;
}
@Override
public void run() {
//不斷消費產品
for( int i = 1; i <= 100; i++){
storate.get();
}
}
}
練習:
package com.wkcto.chapter07.producerconsumer.p2;
/**
* 創建兩個線程,一個線程打印奇數,一個線程打印偶數,實現兩個線程的交替打印
* 線程1 : 1
* 線程2 : 2
* 線程1 : 3
* 線程2 : 4
* 線程1 : 5
* 線程2 : 6
* 線程1 : 7
* @author 蛙課網
*
*/
public class Test {
public static void main(String[] args) {
PrintNum printNum = new PrintNum();
//創建線程打印奇數
new Thread(new Runnable() {
@Override
public void run() {
while( true ){
printNum.printOdd();
}
}
}).start();
//創建線程打印偶數
new Thread(new Runnable() {
@Override
public void run() {
while( true ){
printNum.printEven();
}
}
}).start();
}
}
package com.wkcto.chapter07.producerconsumer.p2;
/**
* 定義一個打印奇數和偶數的類
* @author 蛙課網
*
*/
public class PrintNum {
private int num = 1; //保存要打印的數
//打印奇數
public synchronized void printOdd() {
//當num是偶數時, 需要等待
while( num % 2 == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果是奇數就打印
System.out.println( Thread.currentThread().getName() + " : " + num );
num++; //變為偶數
//通知打印偶數
this.notify();
}
//打印偶數
public synchronized void printEven() {
//當num是奇數時, 需要等待
while( num % 2 != 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果是偶數就打印
System.out.println( Thread.currentThread().getName() + " : " + num );
num++; //變為奇數
//通知打印奇數
this.notify();
}
}