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并发编程:生产者-消费者模式

生产者消费者模型是并发编程的经典模型,生产者模型的核心思想是生产者生产的产品通过一块共享的资源与消费者交互,通过共享资源的交互实现了生产者与消费者的解耦。现在的消息队列使用的也是这种思想。   本文...

java 多线程并发系列之 生产者消费者模式的两种实现

生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。 真实世界中的生产者消费者模式...

Java生产者消费者例子

生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个...

线程同步-生产者消费者问题

在进行多线程编程时,难免还要碰到两个问题,那就线程间的互斥与同步: 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才...

Java线程(三):线程协作-生产者/消费者问题

上一篇:Java线程(二)         上一篇讲述了线程的互斥(同步),但是在很多情况下,仅仅同步是不够的,还需要线程与线程协作(通信),生产者/消费者模式是一个经典的线程同步以及通信的模型。  ...
  • ghsau
  • ghsau
  • 2012-04-06 22:46
  • 33353

生产者/消费者问题的多种Java实现方式

生产者/消费者问题的多种Java实现方式

Java多线程编程中生产者-消费者模式的详解

生产者-消费者模式是一个经典的多线程设计模式,它为多线程的协作提供了良好的解决方案。在生产者-消费者模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程。生产者线程负责提交用户请求,消费者线程...
  • ghuiL
  • ghuiL
  • 2014-11-12 15:24
  • 4371

java多线程之消费者生产者模式

/*@author shijin * 生产者与消费者模型中,要保证以下几点: * 1 同一时间内只能有一个生产者生产 生产方法加锁sychronized * 2 同一时间内只能有一个消费者消费...

java多线程之生产者消费者经典问题

今天研究了一下java多线程,顺便写了一下多线程中的经典问题-----生产者消费者经典问题,参照了网上的各种写法之后自己写了一个,如下所示 /**生产者消费者问题,涉及到几个类 * 第一,这个...

Java多线程通信-利用传统的线程通信wait(),notify()方法实现“生产者消费者模式”

想利用传统的线程通信wait(),notify(),notifyAll()方法,必须依赖于同步监听器的存在,也就是说,对于synchronized修饰的同步方法,因为该类的默认实例(this)就是同步...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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