利用多线程实现消费者问题c语言,多线程经典案例——生产者/消费者有关问题的Java实现与详解...

多线程经典案例——生产者/消费者问题的Java实现与详解

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。下面是生产者/消费者问题的Java实现与详解:

import java.util.Stack;

//import java.sql.Timestamp;

public class ProducerConsumer {

public static void main(String[] args) {

//建立一个存储区

ProductStack ss = new ProductStack();

//添加生产者

Producer p1 = new Producer(ss);

p1.setName("NO.1P");

Producer p2 = new Producer(ss);

p2.setName("NO.2P");

Producer p3 = new Producer(ss);

p3.setName("NO.3P");

Producer p4 = new Producer(ss);

p4.setName("NO.4P");

Producer p5 = new Producer(ss);

p5.setName("NO.5P");

//添加消费者

Consumer c1 = new Consumer(ss);

c1.setName("NO.1C");

Consumer c2 = new Consumer(ss);

c2.setName("NO.3C");

Consumer c3 = new Consumer(ss);

c3.setName("NO.3C");

Consumer c4 = new Consumer(ss);

c4.setName("NO.4C");

Consumer c5 = new Consumer(ss);

c5.setName("NO.5C");

//打开存储区

ss.openStack();

//各角色开始进行生产或消费活动

p1.start();

p2.start();

p3.start();

c1.start();

c2.start();

//活动100ms后停止

try {

Thread.sleep(100);

ss.closeStack();

} catch (InterruptedException e) {

e.printStackTrace();

}

//1秒后重新开始活动

try {

Thread.sleep(1000);

ss.openStack();

} catch (InterruptedException e) {

e.printStackTrace();

}

p4.start();

p5.start();

c3.start();

c4.start();

c5.start();

//活动100ms后再次停止

try {

Thread.sleep(100);

ss.closeStack();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

/**

* 产品

* @author Administrator

*

*/

class Product {

//已生产的产品总数

private static Integer totalProduct = 0;

//产品id(生产日期+生产总数)

private String id = null;

public Product() {

this.id = generateId();

}

private String generateId(){

//类锁 由于所有线程的Product对象不同,故只能用类锁使任何使用该类对象的线程在此处进行同步

synchronized(Product.class){

++totalProduct;

//String genId = new Timestamp(System.currentTimeMillis()).toString().replaceAll(

//"[-,:, ,.]", "")

//+ "-" + totalProduct;

return String.valueOf(totalProduct);

//return genId;

}

}

public String getId() {

return id;

}

}

/**

* 产品存储区 所有生产者和消费者共享

* @author Administrator

*

*/

class ProductStack {

//标志存储区是否打开

private boolean StackOpen = false;

//存储区能容纳的最大产品数

private int capacity = 10;

//当前的产品数

private int Current = 0;

//存放产品的容器

private Product[] ProductArray = new Product[capacity];

//存储区关闭后使用的外部(备用)存储区

private Stack externalStack = new Stack();

/**

* 默认构造方法

*/

public ProductStack(){

}

/**

* 构造方法

* @param capacity 存储区容量

*/

public ProductStack(int capacity){

ProductArray = new Product[capacity];

}

/**

* 存储产品

* @param pt 传入生产出的产品

*/

/*

* 对象锁,相当于方法中加synchronized(this){方法体}

* 所有继承object的类都有一个锁标记(lock flag),当多个线程对同一个对象进行访问时,

* 如果遇到同步代码块,会先检查锁标记是否已经打开:如果已打开,线程就被放到锁池中等待,

* 等其他同步代码块释放了锁标记后才继续执行;如果未打开,则为对象添加一个锁标记,然后再执行。

*/

public synchronized void push(Product pt) {

while (StackOpen && Current == ProductArray.length) {

try {

/*

* 线程释放锁标记,被放入等待池, 当同一对象中的其他同步代码块调用

* notify/notifyAll时,线程被放到锁池中,等其他同步代码块释放锁标记后执行。

*/

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

if(!StackOpen){

externalStack.push(pt);

System.out.println("由于存储区已关闭 ,第" + pt.getId() + "号导出至外部存储区!");

return;

}

ProductArray[Current] = pt;

String threadName = Thread.currentThread().getName();

if(threadName.equals("externalStackImportThread")){

System.out.println("第" + pt.getId() + "号已从外部存储区导入!");

}else{

System.out.println(threadName + "生产的:第" + pt.getId() + "号已入库!");

}

++Current;

/* 释放本对象等待池中的所有线程,进入锁池,等push释放锁标记后,共同竞争以进入running状态

* 此时,存储区至少有一个产品,所以通知在pop中等待的线程,等push结束后,可以相互竞争以继续执行

*/

this.notifyAll();

}

/**

* 取出产品

* @return 返回从库中取出的产品

*/

public synchronized Product pop() {

while (StackOpen && Current == 0) {

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

if(!StackOpen){

return null;

}

--Current;

//此时,存储区至少还有一个产品可存储,所以通知在push中等待的线程,等pop结束后,可以相互竞争以继续执行

this.notifyAll();

Product pt = ProductArray[Current];

System.out.println("----------" + Thread.currentThread().getName() + "消费的:第" + pt.getId() + "号已出库!");

return pt;

}

/**

* 打开存储区

*/

public void openStack(){

System.out.println("-----------------------存储区已打开!现有产品数: " + getCurrent() + "-----------------------");

StackOpen = true;

//导入外部存储区中的产品

if(!externalStack.isEmpty()){

ImportExternalStack();

}

}

/**

* 导入外部存储区

*/

private void ImportExternalStack(){

//使用Runnable匿名类建立一个导入线程

Thread thread = new Thread(new Runnable(){

@Override

public void run() {

// TODO Auto-generated method stub

while(!externalStack.isEmpty()){

Product pt = externalStack.pop();

push(pt);

}

}

});

thread.setName("externalStackImportThread");

thread.start();

}

/**

* 关闭存储区

*/

public synchronized void closeStack(){

StackOpen = false;

//通知所有正在等待的线程“查看”当前库状态

this.notifyAll();

System.out.println("-----------------------存储区已关闭!现有产品数: " + getCurrent() + "-----------------------");

}

/**

* 查询存储区是否打开

* @return

*/

public boolean isStackOpen() {

return StackOpen;

}

/**

* 查询存储区产品的最大存储数量

* @return

*/

public int getMaxProduct() {

return capacity;

}

/**

* 获得当前产品数量

* @return

*/

public int getCurrent() {

return Current;

}

/**

* 获得外部存储区产品数量

* @return

*/

public int getExternalStackCount() {

return externalStack.size();

}

}

/**

* 生产者

* @author Administrator

*

*/

class Producer extends Thread{

ProductStack ss;

public Producer(ProductStack ss) {

this.ss = ss;

}

/**

* 生产产品

*/

public void run() {

while (ss.isStackOpen()) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

Product pt = new Product();

System.out.println(Thread.currentThread().getName() + "生产了:第"

+ pt.getId() + "号");

ss.push(pt);

}

System.out.println(Thread.currentThread().getName() +"已停止生产!");

}

}

/**

* 消费者

* @author Administrator

*

*/

class Consumer extends Thread{

ProductStack ss;

public Consumer(ProductStack ss) {

this.ss = ss;

}

/**

* 消费产品

*/

public void run() {

while (ss.isStackOpen()) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

Product pt = ss.pop();

if(pt != null){

System.out.println("----------" + Thread.currentThread().getName() + "消费了:第"

+ pt.getId() + "号");;

}

}

System.out.println(Thread.currentThread().getName() + "已停止消费");

}

}

输出(结果不唯一):

-----------------------存储区已打开!现有产品数: 0-----------------------

NO.2P生产了:第1号

NO.3P生产了:第3号

NO.1P生产了:第2号

NO.2P生产的:第1号已入库!

----------NO.3C消费的:第1号已出库!

NO.1P生产的:第2号已入库!

----------NO.3C消费了:第1号

NO.3P生产的:第3号已入库!

----------NO.1C消费的:第3号已出库!

----------NO.1C消费了:第3号

NO.2P生产了:第4号

NO.2P生产的:第4号已入库!

----------NO.1C消费的:第4号已出库!

----------NO.1C消费了:第4号

NO.1P生产了:第5号

NO.1P生产的:第5号已入库!

NO.3P生产了:第6号

NO.3P生产的:第6号已入库!

----------NO.3C消费的:第6号已出库!

----------NO.3C消费了:第6号

----------NO.1C消费的:第5号已出库!

----------NO.1C消费了:第5号

NO.3P生产了:第8号

NO.2P生产了:第9号

NO.1P生产了:第7号

NO.3P生产的:第8号已入库!

NO.1P生产的:第7号已入库!

NO.2P生产的:第9号已入库!

----------NO.3C消费的:第9号已出库!

----------NO.3C消费了:第9号

----------NO.1C消费的:第7号已出库!

----------NO.1C消费了:第7号

NO.2P生产了:第10号

NO.1P生产了:第12号

NO.3P生产了:第11号

NO.2P生产的:第10号已入库!

NO.3P生产的:第11号已入库!

NO.1P生产的:第12号已入库!

----------NO.3C消费的:第12号已出库!

----------NO.3C消费了:第12号

----------NO.1C消费的:第11号已出库!

NO.3P生产了:第14号

NO.3P生产的:第14号已入库!

NO.1P生产了:第13号

----------NO.3C消费的:第14号已出库!

NO.2P生产了:第15号

----------NO.1C消费了:第11号

NO.1P生产的:第13号已入库!

----------NO.3C消费了:第14号

NO.2P生产的:第15号已入库!

----------NO.1C消费的:第15号已出库!

----------NO.1C消费了:第15号

NO.1P生产了:第17号

----------NO.3C消费的:第13号已出库!

NO.3P生产了:第16号

NO.1P生产的:第17号已入库!

----------NO.3C消费了:第13号

NO.2P生产了:第18号

NO.3P生产的:第16号已入库!

NO.2P生产的:第18号已入库!

NO.3P生产了:第19号

NO.3P生产的:第19号已入库!

----------NO.3C消费的:第19号已出库!

----------NO.3C消费了:第19号

NO.1P生产了:第20号

NO.1P生产的:第20号已入库!

NO.2P生产了:第21号

NO.2P生产的:第21号已入库!

----------NO.1C消费的:第21号已出库!

----------NO.1C消费了:第21号

-----------------------存储区已关闭!现有产品数: 7-----------------------

NO.3P生产了:第22号

由于存储区已关闭 ,第22号导出至外部存储区!

NO.3P已停止生产!

NO.3C已停止消费

NO.1P生产了:第23号

由于存储区已关闭 ,第23号导出至外部存储区!

NO.1P已停止生产!

NO.2P生产了:第24号

由于存储区已关闭 ,第24号导出至外部存储区!

NO.2P已停止生产!

NO.1C已停止消费

-----------------------存储区已打开!现有产品数: 7-----------------------

第24号已从外部存储区导入!

第23号已从外部存储区导入!

第22号已从外部存储区导入!

----------NO.5C消费的:第22号已出库!

----------NO.5C消费了:第22号

NO.4P生产了:第25号

NO.4P生产的:第25号已入库!

----------NO.3C消费的:第25号已出库!

----------NO.3C消费了:第25号

----------NO.4C消费的:第23号已出库!

----------NO.4C消费了:第23号

NO.5P生产了:第26号

NO.5P生产的:第26号已入库!

----------NO.5C消费的:第26号已出库!

----------NO.5C消费了:第26号

NO.4P生产了:第27号

NO.4P生产的:第27号已入库!

----------NO.4C消费的:第27号已出库!

----------NO.4C消费了:第27号

----------NO.3C消费的:第24号已出库!

NO.5P生产了:第28号

----------NO.3C消费了:第24号

NO.5P生产的:第28号已入库!

----------NO.5C消费的:第28号已出库!

----------NO.5C消费了:第28号

----------NO.3C消费的:第20号已出库!

----------NO.3C消费了:第20号

NO.4P生产了:第29号

NO.4P生产的:第29号已入库!

NO.5P生产了:第30号

NO.5P生产的:第30号已入库!

----------NO.4C消费的:第30号已出库!

----------NO.4C消费了:第30号

----------NO.5C消费的:第29号已出库!

NO.5P生产了:第31号

----------NO.3C消费的:第18号已出库!

----------NO.3C消费了:第18号

----------NO.4C消费的:第16号已出库!

----------NO.4C消费了:第16号

NO.5P生产的:第31号已入库!

----------NO.5C消费了:第29号

NO.4P生产了:第32号

NO.4P生产的:第32号已入库!

----------NO.3C消费的:第32号已出库!

NO.5P生产了:第33号

----------NO.5C消费的:第31号已出库!

----------NO.5C消费了:第31号

----------NO.3C消费了:第32号

NO.4P生产了:第34号

----------NO.4C消费的:第17号已出库!

----------NO.4C消费了:第17号

NO.4P生产的:第34号已入库!

NO.5P生产的:第33号已入库!

----------NO.5C消费的:第33号已出库!

----------NO.5C消费了:第33号

----------NO.3C消费的:第34号已出库!

----------NO.3C消费了:第34号

----------NO.4C消费的:第10号已出库!

NO.4P生产了:第35号

NO.5P生产了:第36号

----------NO.4C消费了:第10号

NO.4P生产的:第35号已入库!

NO.5P生产的:第36号已入库!

----------NO.5C消费的:第36号已出库!

----------NO.5C消费了:第36号

----------NO.3C消费的:第35号已出库!

----------NO.3C消费了:第35号

NO.4P生产了:第37号

NO.4P生产的:第37号已入库!

----------NO.4C消费的:第37号已出库!

----------NO.4C消费了:第37号

NO.5P生产了:第38号

NO.5P生产的:第38号已入库!

-----------------------存储区已关闭!现有产品数: 3-----------------------

NO.5C已停止消费

NO.3C已停止消费

NO.4P生产了:第39号

由于存储区已关闭 ,第39号导出至外部存储区!

NO.4P已停止生产!

NO.4C已停止消费

NO.5P生产了:第40号

由于存储区已关闭 ,第40号导出至外部存储区!

NO.5P已停止生产!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值