生产者消费者模型,最少两个线程,一个生产资源,一个消费资源。 没有资源时,消费者线程需要挂起,等待生产者生产好了再去消费。 生产者生产过多,仓库放不下时,生产者线程需要挂起,等待消费者消费后,仓库腾出地方了再去生产。
就像包子店卖包子。生意火爆时,包子刚出笼就被抢光了,那后来的人在想买就要等待,等待老板再蒸包子,蒸好了再买。 生意不好的时候,蒸好的包子没人买,笼屉里面都是包子。老板想再蒸点包子也没地方放,只能等后来顾客来卖包子了,腾出来笼屉了,才能再蒸。
其中关键点在于,在相应的时间点挂起线程,在相应的时间点唤醒线程。
下面是三种方式的实现实例。
1、object的wait和notify实现生产者消费者
package designmode.productconsumermode.pcwithwaitandnotify;
// object的wait和notify实现生产者消费者
public class ProducerConsumerWithWaitNofity {
public static void main(String[] args) {
Resource resource = new Resource();
//生产者线程
ProducerThread p1 = new ProducerThread(resource);
ProducerThread p2 = new ProducerThread(resource);
ProducerThread p3 = new ProducerThread(resource);
//消费者线程
ConsumerThread c1 = new ConsumerThread(resource);
//ConsumerThread c2 = new ConsumerThread(resource);
//ConsumerThread c3 = new ConsumerThread(resource);
p1.start();
p2.start();
p3.start();
c1.start();
//c2.start();
//c3.start();
}
}
/**
* 公共资源类
*/
class Resource {//重要
//当前资源数量
private int num = 0;
//资源池中允许存放的资源数目
private int size = 1;
/**
* 从资源池中取走资源
*/
public synchronized void remove() {
if (num == size) {
num--;
System.out.println("消费者" + Thread.currentThread().getName() +
"消耗一件资源," + "当前线程池有" + num + "个");
notifyAll();//通知生产者生产资源
} else {
try {
//如果没有资源,则消费者进入等待状态
wait();
System.out.println("消费者" + Thread.currentThread().getName() + "线程进入等待状态");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 向资源池中添加资源
*/
public synchronized void add() {
if (num == 0) {
num++;
System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有"
+ num + "个");
notifyAll(); // 通知消费者消费资源
} else {
//如果当前资源池中有10件资源
try {
wait();//生产者进入等待状态,并释放锁
System.out.println(Thread.currentThread().getName() + "线程进入等待");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者线程
*/
class ConsumerThread extends Thread {
private Resource resource;
public ConsumerThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
// 不断去消耗资源
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.remove();
}
}
}
/**
* 生产者线程
*/
class ProducerThread extends Thread {
private Resource resource;
public ProducerThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
//不断地生产资源
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.add();
}
}
}
2、使用Condition、lock实现生产者消费者
package designmode.productconsumermode.pcwithlockcondition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// 使用Condition、lock实现生产者消费者
public class TestPCwithConditionLock {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition proCd = lock.newCondition();
Condition conCd = lock.newCondition();
Resource resource = new Resource(lock, proCd, conCd);
ProThread pro = new ProThread(resource);
Thread con = new Thread(new ConThread(resource));
Thread con1 = new Thread(new ConThread(resource));
pro.start();
con.start();
con1.start();
}
}
class ProThread extends Thread {
private Resource resource;
public ProThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true) {
try {
sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.product();
}
}
}
class ConThread implements Runnable {
private Resource resource;
public ConThread(Resource resource) {
this.resource = resource;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.consumer();
}
}
}
class Resource {
private int max = 10; // 资源池容量
private int count = 0; // 当前资源数量
private Lock lock;
private Condition proCd;
private Condition conCd;
public Resource(Lock lock, Condition proCd, Condition conCd) {
this.lock = lock;
this.proCd = proCd;
this.conCd = conCd;
}
public void product() {
lock.lock();
try {
if (count < max) {
count++;
System.out.println("线程[" + Thread.currentThread().getName() + "]:正在生产,当前资源池容量为:" + count);
conCd.signalAll();
} else {
proCd.await();
System.out.println("资源池容量已满,停止生产,生产线程[" + Thread.currentThread().getName() + "}挂起");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void consumer() {
lock.lock();
try {
if (count > 0) {
count--;
System.out.println("线程[" + Thread.currentThread().getName() + "]:正在消费,当前资源池容量为:" + count);
proCd.signalAll();
} else {
conCd.await();
System.out.println("资源池容量为0,无法消费,消费线程[" + Thread.currentThread().getName() + "}挂起");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
3、阻塞队列BlockingQueue实现生产者消费者
package designmode.productconsumermode.pcwithblockingqueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
//使用阻塞队列BlockingQueue实现生产者消费者
public class BlockingQueueConsumerProducer {
public static void main(String[] args) {
Resource3 resource = new Resource3();
//生产者线程
ProducerThread3 p = new ProducerThread3(resource);
//多个消费者
ConsumerThread3 c1 = new ConsumerThread3(resource);
ConsumerThread3 c2 = new ConsumerThread3(resource);
p.start();
c1.start();
c2.start();
}
}
/**
* 消费者线程
*/
class ConsumerThread3 extends Thread {
private Resource3 resource3;
public ConsumerThread3(Resource3 resource) {
this.resource3 = resource;
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.remove();
}
}
}
/**
* 生产者线程
*/
class ProducerThread3 extends Thread {
private Resource3 resource3;
public ProducerThread3(Resource3 resource) {
this.resource3 = resource;
}
public void run() {
while (true) {
try {
Thread.sleep((long) (1000 * Math.random()));
} catch (InterruptedException e) {
e.printStackTrace();
}
resource3.add();
}
}
}
class Resource3 {
private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);
/**
* 向资源池中添加资源
*/
public void add() {
try {
resourceQueue.put(1);
System.out.println("生产者" + Thread.currentThread().getName()
+ "生产一件资源," + "当前资源池有" + resourceQueue.size() +
"个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 向资源池中移除资源
*/
public void remove() {
try {
resourceQueue.take();
System.out.println("消费者" + Thread.currentThread().getName() +
"消耗一件资源," + "当前资源池有" + resourceQueue.size()
+ "个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行下实例,再仿着写一下就理解了。
关于wait、notify线程基础知识不太熟悉的可以看这个:https://www.jianshu.com/p/2b56a169866c