Java多线程之使用wait和notify模拟生产者消费者模式

原创 2017年01月10日 17:39:01

本文讲述如何使用Java多线程的wait和notify方法实现最简单的生产者消费者模式。本文假定读者有一定的Java多线程知识,了解wait, notify, notifyAll, synchronized等关键字的作用,同时理解最简单的生产者消费者模式。

 

创建商品仓库

实现一个简单的商品仓库类,用于存储限定容量的商品。当生产者生产商品时,会将商品存入仓库。当消费者消费商品时,会将商品从仓库中取出。

如下代码示例。创建了一个仓库类Box,其中能容纳的最大商品数量为10,当前仓库中商品数量为0。定义了入库方法add和出库方法方法del,用于生产者和消费者调用。

对于入库方法add, 当入库商品过多时,会调用wait暂停当前入库操作,在while循环中等待下次入库。否则,直接入库,并调用notifyAll,唤醒其它线程继续调用入库或出库。

对于出库方法del,当出库商品不足时,会调用wait暂停当前出库操作,在while循环中等待下次出库。否则,直接出库,并调用notifyAll,唤醒其它线程继续调用入库或出库。

在本示例中,用了一个简单Object对象代表要操作的商品集合。当生产者或消费者调用时,都会对商品mObject进行synchronized,保证商品每次只有一个线程对其进行操作,从而保证商品库存的正常,实现了线程的同步。

public class Box {
	public static final int MAX_NUM = 10; // The box can only store MAX_NUM products.
	private int mCurrentNum = 0;          // Current product number in the box
	private Object mObject = new Object();// The products
	
	/**
	 * Produce products.
	 * @param num the product number to produce
	 */
	public void add(int num) {
		synchronized (mObject) {
			while (true) {
				// Too many products to store into the box
				if (mCurrentNum + num > MAX_NUM) {
					System.out.println("Cannot produce: " + num + ", current: " + mCurrentNum);
					try {
						mObject.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} else {
					mCurrentNum += num;
					System.out.println("Produce: " + num + ", current: " + mCurrentNum);
					mObject.notifyAll();
					break;
				}
			}
		}
	}
	
	/**
	 * Consume products.
	 * @param num the product number to consume
	 */
	public void del(int num) {
		synchronized (mObject) {
			while (true) {
				// No enough products in the box
				if (mCurrentNum < num) {
					System.out.println("Cannot consume: " + num + ", current: " + mCurrentNum);
					try {
						mObject.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}				
				} else {
					mCurrentNum -= num;
					System.out.println("Consume: " + num + ", current: " + mCurrentNum);
					mObject.notifyAll();
					break;
				}
			}
		}
	}
}

创建线程

现在分别创建生产者和消费者线程,用于对应一个生产者和一个消费者的入库出库操作。由于入库和出库操作必需为同一个商品仓库,因此先创建一个基类线程,参数为仓库对象,而生产者和消费者都需要继承此线程。

基类线程示例代码:

public class MyThread extends Thread {
	protected Box mBox; // Box to store the products
	protected int mNum; // Product number to produce or consume
		
	public MyThread(Box box, int num) {
		mBox = box;
		mNum = num;
	}
}

生产者线程示例代码:

public class ProducerThread extends MyThread {
	public ProducerThread(Box box, int num) {
		super(box, num);
	}

	@Override
	public void run() {
		super.run();
		mBox.add(mNum);
	}
}


消费者线程示例代码:

public class ConsumerThread extends MyThread {
	public ConsumerThread(Box box, int num) {
		super(box, num);
	}

	@Override
	public void run() {
		super.run();
		mBox.del(mNum);
		
	}
}


 

测试

现在分别创建多个生产者消费者线程,用于测试入库出库操作是否正常。

private static void waitNotifyThread1() {
	final Box box = new Box();
	final Thread[] ts = {
		new ProducerThread(box, 1),
		new ProducerThread(box, 3),
		new ProducerThread(box, 9),
		new ProducerThread(box, 5),
		new ProducerThread(box, 2),
		
		new ConsumerThread(box, 5),
		new ConsumerThread(box, 4),
		new ConsumerThread(box, 5),
		new ConsumerThread(box, 6)
	};
	
	for (Thread t:ts) {
		t.start();
	}	
}

运行结果如下:

Produce: 1, current: 1
Produce: 5, current: 6
Consume: 5, current: 1
Produce: 2, current: 3
Produce: 3, current: 6
Cannot produce: 9, current: 6
Consume: 6, current: 0
Cannot consume: 5, current: 0
Cannot consume: 4, current: 0
Produce: 9, current: 9
Consume: 4, current: 5
Consume: 5, current: 0

注意,实际测试时运行结果可能每次不一样,这正是多线程调度的优势所在。另外,如果读者想自己编译测试,请从此处下载源代码http://download.csdn.net/detail/light_vs_shadow/9734000

上一篇:Java创建与结束线程

下一篇:Java多线程之线程池


【Java笔记】——多线程同步机制模拟生产者/消费者模型

上篇介绍线程,说到线程同步机制,其中说到加锁的机制,如果加锁不合理,则会产生“死锁”。如果加锁的位置合理,则会解决多线程访问同一数据的问题。多线程访问的问题,其中很典型的一个模型就是生产者/消费者模型...
  • u013038861
  • u013038861
  • 2015年09月15日 16:52
  • 2605

java多线程之生产消费模式

/*@author shijin  * 生产者与消费者模型中,要保证以下几点:  * 1 同一时间内只能有一个生产者生产     生产方法加锁sychronized  * 2 同一时间内只能有一...
  • BloodyDmusic
  • BloodyDmusic
  • 2016年07月22日 13:01
  • 871

多线程模拟实现生产者/消费者模型

多线程模拟实现生产者/消费者模型package com.chow.queue;import java.util.concurrent.BlockingQueue; import java.util.c...
  • u013160017
  • u013160017
  • 2017年09月28日 16:15
  • 82

java wait()/notify() 实现生产者消费者模式

java中的多线程会涉及到线程间通信,常见的线程通信方式,例如共享变量、管道流等,这里我们要实现生产者消费者模式,也需要涉及到线程通信,不过这里我们用到了java中的wait()、notify()方法...
  • u014039577
  • u014039577
  • 2016年08月18日 17:54
  • 2191

Java多线程之~~~~使用wait和notify实现生产者消费者模型

在多线程开发中,最经典的一个模型就是生产者消费者模型,他们有一个缓冲区,缓冲区有最大限制,当缓冲区满 的时候,生产者是不能将产品放入到缓冲区里面的,当然,当缓冲区是空的时候,消费者也不能从中拿出来产...
  • a352193394
  • a352193394
  • 2014年09月18日 23:28
  • 7286

利用wait()和notify()实现生产者与消费者问题

生产者与消费者问题是并发编程里面的经典问题,下面用wait()和notify()来实现消费者线程和生产者线程的并发执行。    说之前先讲几个概念:    wait()与sleep()的区...
  • zcxwww
  • zcxwww
  • 2016年05月13日 11:42
  • 2574

【线程同步】java实现生产者消费者问题与线程中的wait与notify总结

JAVA解决线程模型有三种方式,只讲一种:   1、wait()和notify()
  • robert_lizhiqiang
  • robert_lizhiqiang
  • 2014年09月15日 14:41
  • 1129

java多线程-使用notify和wait完成多线程的顺序执行

总结一个关于多线程顺序执行的万能方法。 之前也参考了http://blog.csdn.net/zyplus的博客,觉得写得挺好,但是运行时或多或少又存在着一些小小的问题,算作为对于之前作者文章的一个补...
  • u013376508
  • u013376508
  • 2016年03月16日 10:33
  • 2046

Java 多线程之线程间的通信——wait及notify方法

线程间的相互作用   线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务。   Object类中相关的方法有两个notify方法和三个wait方法:   http://d...
  • free4294
  • free4294
  • 2014年09月11日 14:37
  • 3899

【Java并发编程】之十:使用wait/notify/notifyAll实现线程间通信的几点重要说明

在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调...
  • mmc_maodun
  • mmc_maodun
  • 2013年12月09日 22:09
  • 19745
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java多线程之使用wait和notify模拟生产者消费者模式
举报原因:
原因补充:

(最多只允许输入30个字)