文档章节

生产者和消费问题

零下三度
 零下三度
发布于 2014/09/09 17:54
字数 1220
阅读 114
收藏 9

       本文使用java语言借助java并发库去实现生产者和消费者问题。主要设计思路:1.物料池是共享容器;2.生产者只负责生产物料,添加到物料池中;3.消费者从池中获取物料。在这里使用ReenTranLock控制共享容器的同步,使用Conditona做线程间的通知,当物料池满的时候挂起生产者,并且唤醒消费者去消费池中物料,当池中无物料的时候,挂起消费者,唤醒生产者生产物料。

      在编码之前我需要先对生产者、消费者、物料池做一个简单的分析:

       1.消费者和生产者他们的任务都是单一的,消费者消费物料,生产者生产物料,消费者和生产者对外只需要记住是哪个物料池就行了。

       2.共享数据控制同步应该同一个类中完成,这样控制方便,而且简单。

       3.发出通知的应该是物料池。因为只有它自己知道自己的状态,消费者和生产者才不会关心它。冷暖自知!!

     在做了简单的分析之后,清楚了各个对象的功能。接下来就是设计了。涉及到具体的地方无会在代码中注释,就不在这干巴巴的说了。

     核心-物料池

package com.autonavi.pc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/***
 * 物料池
 * @author 零下三度
 *
 */
public class Pool {
	
	private ReentrantLock lock = new ReentrantLock();
	private Condition putCondition = lock.newCondition();
	private Condition getCondition = lock.newCondition();
	private Product[] productPool = new Product[10];
	private int size;//池中物料的数量
	private int currPutIndex;//当前添加物料的索引
	private int currGetIndex;//当前获取物料的索引
	private Pool(){
		size = 0;
		currPutIndex = 0;
		currGetIndex = 0;
	}
	
	public static Pool getPool(){
		return new Pool();
	}

	/**
	 * 生产者向物料池添加一个商品
	 * @param product
	 * @throws InterruptedException 
	 */
	public void put(Product product) throws InterruptedException{
		try{
			lock.lock();
			//如果物料池满了,则不再允许向物料池中添加物料。
			while(size == productPool.length){
				System.out.println("物料池已经满了,暂时不能添加产品了,请耐心等待.....当前池中物料为:"+size);
				putCondition.await();
			}
			productPool[currPutIndex] = product;
	        if(++currPutIndex == productPool.length){
	        	currPutIndex = 0;
	        }
			++size;
			//注意:由于终端是共享资源,放在此处才能看到真正的测试结果过
			System.out.println(product.toString()+"已经添加到物料池中,当前池中产品个数:"+size+",currPutIndex="+currPutIndex);
			//添加了物料,池中有可用的物料,通知消费者可以从池中获取物料
			getCondition.signal();
		}finally{
			lock.unlock();
		}
	}
	/***
	 * 消费者从物料池中获取一个商品。
	 * @return
	 * @throws InterruptedException 
	 */
	public Product get() throws InterruptedException{
		try{
			lock.lock();
			//如果池中没有物料,则禁止消费者从池中获取物料
			while(size == 0){
				System.out.println("目前没有物料,暂时无法获取产品,请耐心等待.....当前池中物料数量:"+size);
				getCondition.await();
			}
			Product p = productPool[currGetIndex];
			productPool[currGetIndex] = null;
			if(++currGetIndex == productPool.length){
				currGetIndex = 0;
			}
			--size;
			System.out.println("出库的是:"+p.toString()+"当前池中还有产品个数:"+size+",currGetIndex="+currGetIndex);
			putCondition.signal();
			return p;
		}finally{
			lock.unlock();
		}
	}
}

生产者:

package com.autonavi.pc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/***
 * 生产者
 * @author 零下三度
 *
 */
public class Producers implements Runnable{
	
	private AtomicLong id = new AtomicLong(0);
	private Pool pool;
	private String productName;
	
	public Producers(){
	}
	
	public Producers(Pool pool,String productName,AtomicLong id){
		this.id = id;
		this.pool = pool;
		this.productName = productName;
	}

	public Pool getPool() {
		return pool;
	}


	public void setPool(Pool pool) {
		this.pool = pool;
	}

	public String getProductName() {
		return productName;
	}


	public void setProductName(String productName) {
		this.productName = productName;
	}

	
	public AtomicLong getId() {
		return id;
	}

	
	public void setId(AtomicLong id) {
		this.id = id;
	}


	/***
	 * 生产者的工作就是生产商品,添加到物料吃中
	 * 至于什么时候停止,什么时候开始,是需要被人去给他消息的。
	 */
	public void run() {
		Product p;
		try {
			while(true){
				TimeUnit.MILLISECONDS.sleep(200);
				p = new Product(""+id.incrementAndGet(),productName);
				pool.put(p);
				
			} 
		}catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void start(){
		Thread t = new Thread(this);
		t.start();
	}
	

}

消费者:

package com.autonavi.pc;

import java.util.concurrent.TimeUnit;

/***
 * 消费者
 * @author 零下三度
 *
 */
public class Consumers implements Runnable{
	
	private Pool pool;
	
	

	public Pool getPool() {
		return pool;
	}



	public void setPool(Pool pool) {
		this.pool = pool;
	}



	/***
	 * 消费者的工作就是消费物料池中的商品
	 */
	public void run() {
		try {
			Product p;
			while(true){
				TimeUnit.MILLISECONDS.sleep(200);
				p = pool.get();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void start(){
		Thread t = new Thread(this);
		t.start();
	}

}

 物料-产品:

package com.autonavi.pc;
/***
 * 商品
 * @author 零下三度
 *
 */
public class Product {

	private String id;
	private String name;
	
	public Product(){
		
	}
	
	public Product(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	
	@Override
	public String toString() {
		String val = "id:"+id+"\n"+"name:"+name+"\n";
		return val;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj != null && obj instanceof Product){
			Product p = (Product)obj;
			if(this.id != null && this.id.equals(p.getId())){
				return true;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		return id.hashCode();
	}
	
	
	
	
}

测试用例:

package com.autonavi.pc;

import java.util.concurrent.atomic.AtomicLong;

public class ProductsAndConsumersTest {

	public static void main(String[] args) throws InterruptedException {
		Pool pool = Pool.getPool();
		Producers p = new Producers(pool,"产品A",new AtomicLong(0));
		System.out.println("启动生产者");
		p.start();
		Consumers c = new Consumers();
		c.setPool(pool);
		System.out.println("启动消费者");
		c.start();

	}

}


© 著作权归作者所有

零下三度
粉丝 8
博文 11
码字总数 13153
作品 0
朝阳
程序员
私信 提问
一个线程的疑惑

无事实现了一下多线程的生产者消费者问题,发现了一些问题,虽然给出了思路,看看大家的意见 仓库程序 消费者程序 生产者程序 测试程序,一个生产者10个消费者 启动运行后出现了库存量是负数的情...

刘柳
2011/09/15
391
6
线程通信(生产者与消费者问题)

1、线程通信的必要性 多线程不仅共享资源,而且相互牵制向前运行。 2、线程通信的方法(都是在Object中定义) 3个方法: 1) wait() 可运行转入阻塞状态,放锁 2) notify() 阻塞转入可运行状态...

学而时习之
2015/03/11
0
0
Java并发编程初级篇(十二):使用wait和notify生产者消费者问题

在这里我们模拟一个生产者消费者问题。定义一个缓冲区,生产者生产数据并存入缓冲区,消费者从缓冲区中消费数据。缓冲区有固定大小,当缓冲区达到最大时生产者被挂起并等待消费者消费数据后再...

阿拉德大陆的魔法师
2016/11/24
15
0
关于Object#wait() 的虚假唤醒

先看关于wait()方法的javadoc描述 而最后一句话便是本篇文章的重点:虚假唤醒。先看例子: 消费方法

暗中观察
02/26
0
0
Java多线程学习(七)

等待/通知模式中最经典的案例当属生产者/消费者模式,此模式有几种变形,但都是基于wait/notify的。 生产者/消费者模式有两种类型:操作值的和操作栈的。下面分别从这两方面来讲解生产者/消费...

kakayang2011
2016/03/07
42
0

没有更多内容

加载失败,请刷新页面

加载更多

定时获取服务器时间戳的一个类(Typescript)

export class TimeStampService { private _localTimestamp: number; // 本地时间戳 private _serveTimestamp: number; // 服务器端时间戳 private _duration: number = 1000 ......

lilugirl
32分钟前
1
0
前段技术总结

前端UI框架组件库: 说到前端框架我第一印象中想起React、Vue和Angular,不知道你是否与我一样想到这些,现在常用的有:Bootstrap、jQuery UI、BootMetro、AUI常用的还有很多、就不一一跟大家...

WinkJie
51分钟前
1
0
对话亲历者|鲁肃:我在支付宝“拧螺丝“的日子

摘要: 他是支付宝技术平台的奠基人之一,但是他总说“这还不是我心中最完美的架构”;他行事低调但却有着“此时此地,非我莫属”的豪气;他曾无数次充当救火大队长,但自评只是“没有掉队的...

阿里云云栖社区
59分钟前
7
0
设置 npm yarn 淘宝源

设置npm config set chromedriver_cdnurl=http://cdn.npm.taobao.org/dist/chromedriver设置yarn config set "chromedriver_cdnurl" "https://npm.taobao.org/mirrors/chromedriver"......

internetafei
今天
2
0
Docker搭建Mysql集群、主从同步复制

1、创建数据挂载点: mkdir /opt/mysql-master/mysql、/opt/mysql-master/conf.d、/opt/mysql-slave/mysql、/opt/mysql-slave/conf.d 2、分别在master、slave节点文件目录conf.d下创建touch......

WALK_MAN
今天
16
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部