Java 模拟生产者消费者问题
- 格式:doc
- 大小:57.50 KB
- 文档页数:5
生产者消费者实验报告生产者消费者实验报告引言:生产者消费者模型是计算机科学中的一个经典问题,用于解决多线程并发访问共享资源的同步问题。
在本实验中,我们通过编写一个简单的Java程序来模拟生产者消费者模型,并观察其运行结果和效果。
一、实验背景生产者消费者模型是一种常见的并发模型,用于解决多线程访问共享资源时可能出现的数据竞争和同步问题。
在该模型中,生产者负责生产数据并将其放入共享缓冲区,而消费者则负责从缓冲区中取出数据进行消费。
为了确保生产者和消费者之间的同步与互斥,需要使用合适的同步机制,如信号量、互斥锁等。
二、实验目的本实验的主要目的是通过编写一个简单的生产者消费者程序,验证该模型在多线程环境下的正确性和效果。
我们将通过观察程序的输出结果和运行时间来评估其性能,并分析其中可能存在的问题和改进空间。
三、实验设计1. 编写生产者类和消费者类:我们首先定义了一个共享缓冲区,用于存储生产者生产的数据。
然后,我们编写了一个生产者类和一个消费者类,分别实现了生产者和消费者的逻辑。
在生产者类中,我们使用了一个循环来模拟生产者不断地生产数据,并将其放入缓冲区。
而在消费者类中,我们同样使用了一个循环来模拟消费者不断地从缓冲区中取出数据进行消费。
2. 同步机制的选择:为了保证生产者和消费者之间的同步与互斥,我们选择了信号量作为同步机制。
在生产者类中,我们使用一个信号量来控制缓冲区的可用空间,当缓冲区已满时,生产者将等待,直到有可用空间。
而在消费者类中,我们同样使用一个信号量来控制缓冲区的可用数据,当缓冲区为空时,消费者将等待,直到有可用数据。
3. 实验参数的设置:为了模拟真实的生产者消费者场景,我们设置了以下参数:- 缓冲区大小:10- 生产者数量:3- 每个生产者生产的数据量:1000- 消费者数量:2四、实验结果与分析在运行实验程序后,我们观察到以下结果:1. 生产者和消费者之间的同步与互斥得到了有效保证,生产者在缓冲区已满时会等待,直到有可用空间;消费者在缓冲区为空时会等待,直到有可用数据。
用JAVA模拟生产者与消费者的实例模拟生产者与消费者的实例,生产者生产一个产品,消费者就消费一个产品,然后生产者再生产,消费者再消费。
要求整套源码,程序能独立运行的。
使用的生产者和消费者模型具有如下特点:(1)本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。
生产者可以把产品放到目前某一个空缓冲区中。
(2)消费者只消费指定生产者的产品。
(3)在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。
(4)本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。
而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。
Windows 用来实现同步和互斥的实体。
在Windows 中,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)和事件(Event)等。
本程序中用到了前三个。
使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。
这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。
当然,在进程间使用这些同步对象实现同步的方法是类似的。
1.用锁操作原语实现互斥为解决进程互斥进人临界区的问题,可为每类临界区设置一把锁,该锁有打开和关闭两种状态,进程执行临界区程序的操作按下列步骤进行:①关锁。
先检查锁的状态,如为关闭状态,则等待其打开;如已打开了,则将其关闭,继续执行步骤②的操作。
②执行临界区程序。
③开锁。
将锁打开,退出临界区。
2.信号量及WAIT,SIGNAL操作原语信号量的初值可以由系统根据资源情况和使用需要来确定。
在初始条件下信号量的指针项可以置为0,表示队列为空。
//java多线程模拟生产者消费者问题//ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品//Storage仓库public class ProducerConsumer {public static void main(String[] args) {Storage s = new Storage();Producer p = new Producer(s);Consumer c = new Consumer(s);Thread tp = new Thread(p);Thread tc = new Thread(c);tp.start();tc.start();}}class Consumer implements Runnable {//消费者Storage s = null;public Consumer(Storage s){this.s = s;}public void run() {for(int i=0; i<20; i++){Product p = s.pop();//取出产品try {Thread.sleep((int)(Math.random()*1500));} catch (InterruptedException e) {e.printStackTrace();}}}}class Producer implements Runnable {//生产者Storage s = null;public Producer(Storage s){this.s = s;}public void run() {for(int i=0; i<20; i++){Product p = new Product(i);s.push(p); //放入产品// System.out.println("生产者放入:" + p);try {Thread.sleep((int)(Math.random()*1500));} catch (InterruptedException e) {e.printStackTrace();}}}}class Product {int id;public Product(int id){this.id = id;}public String toString(){//重写toString方法return"产品:"+this.id;}}class Storage {int index = 0;Product[] products = new Product[5];public synchronized void push(Product p){//放入while(index==this.products.length){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.products[index] = p;System.out.println("生产者放入"+index+"位置:" + p);index++;this.notifyAll();}public synchronized Product pop(){//取出while(this.index==0){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}index--;this.notifyAll();System.out.println("消费者从"+ index+ "位置取出:"+ this.products[index]);return this.products[index];}}。
网络编程实验报告实验题目:生产者/消费者问题*名:**学号:**********班级:信息安全091班完成时间:2011.10.25—2011.11.05 ****: ***一、实验概述1.1 实验目的了解进程的同步、互斥机制,认识理解其过程,并用于解决生产者/消费者问题。
使用java编程实现“生产者——消费者”多线程同步问题。
1.2任务描述有两个生产者,每个生产者每次可以生产1个产品,有一个消费者每次消费2个产品,仓库最多只能存放2个产品,若仓库满,则生产者需等待空位来存放产品,若仓库产品数量不足,则消费者需等待来消费产品。
请用多线程技术实现以上功能,要求生产者存放产品时按先来先服务的队列原则来存放产品。
二、功能及处理逻辑设计2.1具体要求1.三个线程。
t0,t1分别代表生产者A,生产者B。
t2代表消费者consumer2.一个仓库(缓冲区),最大存量为两个产品2.1 功能及模块设计2.2特别功能1. Thread.sleep((int)(Math.random()方法令线程随机发生。
2. 用synchronized来实现同步,当仓库满时,等待消费线程,若发生生产者线程则立即等待,进入沉睡状态,当消费线程发生时,同时逐一激活已沉睡生产进程,实现先来先服务。
3. 用synchronized来实现同步,当仓库未满时,发生消费线程,则等待(睡眠),当发生线程,使仓库数为2,激活消费线程。
4. 定义一个新线程必须重写父类的run方法。
2.3算法搭建三、源代码及方法解释(重点步骤已用红色注释)本次方法中未用到队列,利用的是多次调用线程,逐一实现先来先服务import java.util.*;public class xiancheng{public static void main(String[] args){StoreHouse storeHouse = new StoreHouse();Producer producer1 = new Producer("生产者A", storeHouse);Producer producer2 = new Producer("生产者B", storeHouse);Consumer comsumer = new Consumer("消费者", storeHouse);Thread t0 = new Thread(producer1);Thread t1 = new Thread(producer2);Thread t2 = new Thread(comsumer);t0.start();t1.start();t2.start();}}class Producer extends Thread implements Runnable //定义生产者线程{private String producerName = null;private StoreHouse storeHouse = null;public Producer(String producerName, StoreHouse storeHouse) {this.producerName = producerName;this.storeHouse = storeHouse;} //声明生产者要放产品的仓库public void setProducerName(String producerName){this.producerName = producerName;}public String getProducerName(){return producerName;}public void run()//定义一个新线程必须重写父类的run方法{while (true){storeHouse.store_in(this);try{Thread.sleep((int)(Math.random() * 2500));}//定义线程休眠时间catch (InterruptedException e){return;}//有可能抛出异常,必须对它进行捕捉}}}class Consumer extends Thread implements Runnable{//定义消费者线程public String consumerName = null;public StoreHouse storeHouse = null;public Consumer(String consumerName, StoreHouse storeHouse){this.consumerName = consumerName;this.storeHouse = storeHouse;}public void setConsumerName(String consumerName){this.consumerName = consumerName;}public String getConsumerName(){return consumerName;}public void run(){while (true){storeHouse.store_out(this);try{Thread.sleep((int)(Math.random() * 5000)); } //定义线程休眠时间catch (InterruptedException e){return;}}}}class StoreHouse{int count = 0;//创建仓库,用来放产品public synchronized void store_in(Producer pro){while (count == 2) //仓库容量为2{System.out.println("仓库已满," + pro.getProducerName() + "正等待生产...");try{this.wait();//生产者线程进入沉睡}catch (InterruptedException e){}}count++;//产品数自加1System.out.println(pro.getProducerName() + " 生产了 1个产品,库存为" + count); //激活等待的线程,实现先来先服务notify();}public synchronized void store_out(Consumer con){while (count == 0 || count == 1){try{System.out.println("仓库数量不足,消费者等待消费...");this.wait();}catch (InterruptedException e){}}count = count-2;System.out.println(con.getConsumerName() + " 消费了 2个产品,库存为" + count);notify();}}四、程序截图1.先来先服务效果2.消费者等待情况消费者等待的前提下,当仓库数为时立即激活线程,消费当消费者等待时,若仓库每增加一个商品,总会检验是否为满,为则激活消费3.程序效果图总览:其中体现了线程随机性发生,等等各方面情况五、实验总结本次试验我基本上掌握了java多线程同步的方法,完成老师的任务,但是熟练程度还远远未够,将来我也必须更加努力,力求让自己java 编程能力更强。
操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)1、问题引⼊:什么是⽣产者消费者问题?⽣产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是⼀个多线程同步问题的经典案例。
该问题描述了共享固定⼤⼩缓冲区的两个线程——即所谓的“⽣产者”和“消费者”——在实际运⾏时会发⽣的问题。
⽣产者的主要作⽤是⽣成⼀定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证⽣产者不会在缓冲区满时加⼊数据,消费者也不会在缓冲区中空时消耗数据。
.要解决该问题,就必须让⽣产者在缓冲区满时休眠(要么⼲脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,⽣产者才能被唤醒,开始往缓冲区添加数据。
同样,也可以让消费者在缓冲区空时进⼊休眠,等到⽣产者往缓冲区添加数据之后,再唤醒消费者。
通常采⽤进程间通信的⽅法解决该问题。
如果解决⽅法不够完善,则容易出现死锁的情况。
出现死锁时,两个线程都会陷⼊休眠,等待对⽅唤醒⾃⼰。
该问题也能被推⼴到多个⽣产者和消费者的情形。
2、问题分析该问题需要注意的⼏点:1. 在缓冲区为空时,消费者不能再进⾏消费2. 在缓冲区为满时,⽣产者不能再进⾏⽣产3. 在⼀个线程进⾏⽣产或消费时,其余线程不能再进⾏⽣产或消费等操作,即保持线程间的同步4. 注意条件变量与互斥锁的顺序由于前两点原因,因此需要保持线程间的同步,即⼀个线程消费(或⽣产)完,其他线程才能进⾏竞争CPU,获得消费(或⽣产)的机会。
对于这⼀点,可以使⽤条件变量进⾏线程间的同步:⽣产者线程在product之前,需要wait直⾄获取⾃⼰所需的信号量之后,才会进⾏product的操作;同样,对于消费者线程,在consume之前需要wait直到没有线程在访问共享区(缓冲区),再进⾏consume的操作,之后再解锁并唤醒其他可⽤阻塞线程。
JAVA⽣产者消费者模型⽣产者消费者问题(Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是⼀个多线程同步问题的经典案例。
⽣产者⽣成⼀定量的数据放到缓冲区中,然后重复此过程;与此同时,消费者也在缓冲区消耗这些数据。
⽣产者和消费者之间必须保持同步,要保证⽣产者不会在缓冲区满时放⼊数据,消费者也不会在缓冲区空时消耗数据。
实现该模型具有不⽌⼀种办法,本篇采⽤wait(),notifyAll()来实现,具体说明见代码注释。
⽣产者和消费者我设定了⼀定的sleep时间,以贴合实际并⽅便观察结果。
仓库public class Storage {//仓库类//仓库的最⼤容量private final int maxSize=10;//仓库当前货物数量private int currentSize=0;//⽣产⽅法public synchronized void produce() { //注意⼀定要使⽤while循环阻塞不满⾜条件的情况while(currentSize>=maxSize) { //wait()之后再次被唤醒将从wait后继续执⾏所以使⽤if不⾏System.out.println(Thread.currentThread().getName()+"仓库已满");try {wait();} catch (InterruptedException e) {}}currentSize++;System.out.println(Thread.currentThread().getName()+"⽣产了⼀个产品现库存为"+currentSize);notifyAll();}//消费⽅法public synchronized void consume() {while(currentSize==0) {System.out.println(Thread.currentThread().getName()+"仓库已空");try {wait();} catch (InterruptedException e) {// TODO: handle exception}}currentSize--;System.out.println(Thread.currentThread().getName()+"消费类⼀个产品现库存为"+currentSize);notifyAll();}}⽣产者public class Producer implements Runnable {private Storage s;public Producer(Storage s) {this.s = s;}@Overridepublic void run() {while(true) {try {Thread.sleep(1000);s.produce();} catch (InterruptedException e) {// TODO: handle exception}}}}消费者public class Consumer implements Runnable { private Storage s;public Consumer(Storage s) {this.s = s;}@Overridepublic void run() {while(true) {try {Thread.sleep(3000);s.consume();} catch (InterruptedException e) {// TODO: handle exception}}}}测试public class test {public static void main(String[] args) {Storage s=new Storage();new Thread(new Producer(s),"⽣产者1").start(); new Thread(new Producer(s),"⽣产者2").start(); new Thread(new Producer(s),"⽣产者3").start(); new Thread(new Consumer(s),"消费者1").start(); new Thread(new Consumer(s),"消费者2").start(); new Thread(new Consumer(s),"消费者3").start(); }}。
操作系统⽣产者-消费者问题(PV操作)(Java实现)⼀、问题描述⼀组⽣产者进程和⼀组消费者进程共享⼀个初始为空、⼤⼩n的缓冲区,只有缓冲区没满时,⽣产者才能把资源放⼊缓冲区,否则必须等待;只有缓冲区不为空时,消费者才能从中取出资源,否则必须等待。
由于缓冲区是临界资源,它只允许⼀个⽣产者放⼊资源,或⼀个消费者从中取出资源。
⼆、问题分析(1)、关系分析。
⽣产者和消费者对缓冲区互斥访问是互斥关系,同时⽣产者和消费者⼜是⼀个相互协作的关系,只有⽣产者⽣产之后,消费者只能才能消费,它们还是同步关系。
(2)、整理思路。
只有⽣产⽣产者和消费者进程,正好是这两个进程存在着互斥关系和同步关系,即需要解决的是互斥和同步 PV 操作的位置。
(3)、信号量设置。
信号量 mutex 作为互斥信号量,⽤于控制互斥访问缓冲池,互斥信号量初值为1;信号量 full ⽤于记录当前缓冲池中的“满”缓冲池,初值为0;信号量 empty ⽤于记录当前缓冲池中“空“缓冲区数,初值为n。
三、代码实现import java.util.Scanner;public class ProCon {public static void main(String[] args){int producer,consumer;Scanner sc=new Scanner(System.in);System.out.print("请输⼊⽣产者数⽬:");producer=sc.nextInt();//输⼊⽣产者数量System.out.print("请输⼊消费者数⽬:");consumer=sc.nextInt();//输⼊消费者数量for(int i=0;i<producer;i++){new Thread(new Producer(),"⽣产者"+ Integer.toString(i)+"号").start();//创建⽣产者线程并开启}for(int j=0;j<consumer;j++){new Thread(new Consumer(),"消费者"+ Integer.toString(j)+"号").start();//创建消费者线程并开启}}}class Global{public static Semaphore empty=new Semaphore(3);//空闲缓冲区初始化为三public static Semaphore full=new Semaphore(0);//满缓冲区初始化为空public static Semaphore mutex=new Semaphore(1);//临界区互斥信号量public static int count=0;//count⽤于缓冲区中的进程进⾏计数//定时等待public static void timingwait(){try{Thread.sleep(2000);//Thread.Sleep()⽅法⽤于将当前线程休眠⼀定时间时间单位是ms,1s=1000ms}catch(InterruptedException e)//当使⽤ng.Thread类的sleep⽅法时,可能会导致线程阻塞,需要抛出InterruptedException(中断异常)异常{e.printStackTrace();}}}//⽣产者class Producer implements Runnable//Runnable接⼝创建新线程{@Overridepublic void run()//Runnable 接⼝可以被任何想要被⼀个线程运⾏的接⼝继承实现;继承 Runnable 接⼝的类必须有⼀个 run() ⽅法{Global.timingwait();Global.timingwait();System.out.println(Thread.currentThread().getName()+" ⽣产出⼀个商品...");//Thread.currentThread().getName()获得当前执⾏的线程Global.empty.P();//获取空缓冲区单元Global.mutex.P();//进⼊临界区Global.timingwait();System.out.println(Thread.currentThread().getName()+" 将产品放⼊缓冲区--缓冲区剩余 "+(++Global.count)+" 个产品");Global.mutex.V();//离开临界区,释放信号量Global.full.V();//满缓冲区数加⼀}}//消费者class Consumer implements Runnable{@Overridepublic void run(){Global.timingwait();Global.full.P();//获取满缓冲区单元Global.mutex.P();//进⼊临界区Global.timingwait();System.out.println(Thread.currentThread().getName()+" 从缓冲区取出⼀个产品--缓冲区剩余 "+(--Global.count)+" 个产品");Global.mutex.V();//离开临界区,释放互斥信号量Global.empty.V();//空缓冲区加⼀System.out.println(Thread.currentThread().getName()+" 消费⼀个商品...");}}//信号量class Semaphore{public int value;public Semaphore(int value){super();this.value=value;}//P操作public synchronized final void P()//使⽤synchronized修饰的⽅法,叫做同步⽅法,保证A线程执⾏该⽅法的时,其他线程只能在⽅法外等着.{//被final修饰的⽅法是⼀个最终⽅法,不能被重写,重写会报错value--;if(value<0){try{this.wait();//当缓冲区已满/空时,⽣产者或消费者线程停⽌⾃⼰的执⾏,释放锁,使⾃⼰处于等待状态,让其它线程执⾏}catch(InterruptedException e)//当使⽤ng.Thread类的 wait⽅法时,可能会导致线程阻塞,需要抛出InterruptedException(中断异常)异常{e.printStackTrace();}}}//V操作public synchronized final void V(){value++;if(value<=0){this.notify();//当⽣产者或消费者向缓冲区放⼊或取出⼀个产品时,向其他等待的线程发出通知,同时释放锁,使⾃⼰处于等待状态,让其它线程执⾏。
import ponent;import java.awt.Container;import java.awt.Graphics;import java.awt.GridLayout;import java.awt.Image;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.BorderFactory;import javax.swing.Icon;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;//通过本次实验,知晓两个问题:1.repaint()方法不能在主方法(主类)中使用(否则会引起背景透明问题);2.默认布局会引起组件覆盖问题。
//bug1:如果非第一次执行开始模拟按钮index值为零,程序会直接退出;//bug2:当产品为零时,点恢复模拟,因为生产者较快。
仓库第一格会没有产品.//bug3:生产速度必须大于等于生产速度;不要问我为什么,老子也很烦恼.//如果有大神解决了BUG请回传给我谢谢public class consumerandproducer extends JFrame{private static final long serialVersionUID = 1L;public static JLabel jl5=new JLabel();public static int index=0;Icon icon=new ImageIcon("E://OS experiment//22.jpg");public static JLabel jl6=new JLabel("jl6");public static JLabel jl8=new JLabel("jl8");public static JLabel jl7=new JLabel("jl8");public static JLabel jl9=new JLabel("jl9");public static JLabel jl10=new JLabel("jl10");public static JLabel jl11=new JLabel("jl11");public static JLabel jl12=new JLabel("jl12");public static JLabel jl13=new JLabel("jl13");public static JLabel jl14=new JLabel("jl14");public static JLabel jlabel;public static JLabel mark;//为生产按钮设置标记public static JLabel mark1;//为消费按钮设置标记testing11 test=new testing11();testing22 test2=new testing22();Container ff=this.getContentPane();public consumerandproducer(String title){super(title);ff.add(test);ff.add(test2);setBounds(200,200,900,653);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLayout(null);jl5.setBounds(620,40,200,200);jl5.setBorder(BorderFactory.createEtchedBorder());jl5.setLayout(new GridLayout(3,3));add(jl5);jlabel=new JLabel("消息显示器");jlabel.setBounds(2,500,390,100);jlabel.setBorder(BorderFactory.createEtchedBorder());add(jlabel);mark=new JLabel("生产进行中");mark1=new JLabel("消费进行中");add(mark);add(mark1);jl6.setSize(20,20);jl7.setSize(20,20);jl8.setSize(20,20);jl9.setSize(20,20);jl10.setSize(20,20);jl11.setSize(20,20);jl12.setSize(20,20);jl13.setSize(20,20);jl14.setSize(20,20);jl5.add(jl6);jl5.add(jl7);jl5.add(jl8);jl5.add(jl9);jl5.add(jl10);jl5.add(jl11);jl5.add(jl12);jl5.add(jl13);jl5.add(jl14);jl6.setBorder(BorderFactory.createEtchedBorder());jl7.setBorder(BorderFactory.createEtchedBorder());jl8.setBorder(BorderFactory.createEtchedBorder());jl9.setBorder(BorderFactory.createEtchedBorder());jl10.setBorder(BorderFactory.createEtchedBorder());jl11.setBorder(BorderFactory.createEtchedBorder());jl12.setBorder(BorderFactory.createEtchedBorder());jl13.setBorder(BorderFactory.createEtchedBorder());jl14.setBorder(BorderFactory.createEtchedBorder());}public static void main(String args[]){consumerandproducer frame = new consumerandproducer("模拟消费者生产者实验");frame.setVisible(true);frame.setLayout(null);Thread3 tt=new Thread3(frame);tt.start();}}//生产者线程class testing22 extends JPanel{private static final long serialVersionUID = 1L;public static Thread1 dd1=new Thread1();public static ImageIcon icon;public static int x=0,y=60;JLabel jl3;Image icon1;JButton jb3,jb4;public testing22(){setLayout(null);this.setBounds(38,78,320,270);icon=new ImageIcon("E://OS experiment//22.jpg");icon1=icon.getImage();final JButton jb3=new JButton("开始消费");final JButton jb4=new JButton("停止消费");JLabel jl6 = new JLabel("模拟消费者");jl6.setBounds(125,5,75,30);this.add(jl6);jl6.setBorder(BorderFactory.createEtchedBorder());this.add(jb3);this.add(jb4);jb3.setBounds(45,146,120,50);jb4.setBounds(175,146,120,50);jb4.addActionListener(new ActionListener(){@SuppressWarnings("deprecation")public void actionPerformed(ActionEvent e){if(e.getSource()==jb4&&e.getActionCommand().equals("停止消费")){dd1.suspend();consumerandproducer.mark1.setText("消费已停止");}}});jb3.addActionListener(new ActionListener(){@SuppressWarnings("deprecation")public void actionPerformed(ActionEvent e){if(e.getSource()==jb3&&e.getActionCommand().equals("开始消费")){if(consumerandproducer.index<1){dd1.suspend();consumerandproducer.jlabel.setText("仓库里没有产品或已经消费完毕!");consumerandproducer.mark1.setText("消费进行中");}dd1.resume();return;}}});}public void paint(Graphics g){if(x>getWidth()){x=-50;if(consumerandproducer.mark.getText()=="生产进行中"){testing11.dd.resume();}if(consumerandproducer.index<2){dd1.suspend();// testing11.dd.suspend();}Component[] labels = consumerandproducer.jl5.getComponents ();((JLabel)labels[--consumerandproducer.index]).setIcon (null);if(consumerandproducer.index==0){consumerandproducer.jlabel.setText("仓库产品已消费完毕,请生产产品或者恢复模拟!");}if(consumerandproducer.index!=0){consumerandproducer.jlabel.setText("消费状态下当前仓库产品数量为:"+consumerandproducer.index);}}super.paint(g);g.drawImage(icon1, x, y, jl3);repaint();}}class Thread1 extends Thread{public void run(){while(true){testing22.x+=10;try{Thread2.sleep(50);} catch (InterruptedException e){e.printStackTrace();}}}}//消费者线程class testing11 extends JPanel{private static final long serialVersionUID = 1L;public static Thread2 dd=new Thread2();public static ImageIcon icon;public static int x=0,y=60;JLabel jl1;Image icon1;JButton jb1,jb2;public testing11(){setLayout(null);this.setBounds(420,400,320,440);icon=new ImageIcon("E://OS experiment//22.jpg");icon1=icon.getImage();final JButton jb1=new JButton("开始生产");final JButton jb2=new JButton("停止生产");JLabel jl3 = new JLabel("模拟生产者");jl3.setBounds(125,5,75,30);this.add(jl3);jl3.setBorder(BorderFactory.createEtchedBorder());this.add(jb1);this.add(jb2);jb1.setBounds(45,146,120,50);jb2.setBounds(175,146,120,50);jb2.addActionListener(new ActionListener(){@SuppressWarnings("deprecation")public void actionPerformed(ActionEvent e){if(e.getSource()==jb2&&e.getActionCommand().equals("停止生产")){dd.suspend();consumerandproducer.mark.setText("生产已停止");}}});jb1.addActionListener(new ActionListener(){@SuppressWarnings("deprecation")public void actionPerformed(ActionEvent e){if(e.getSource()==jb1&&e.getActionCommand().equals("开始生产")&&consumerandproducer.index!=9){dd.resume();consumerandproducer.mark.setText("生产进行中");return;}if(e.getSource()==jb1&&e.getActionCommand().equals("开始生产")&&consumerandproducer.index==9){consumerandproducer.jlabel.setText("仓库已满,生产停止,请先消费!");}}});}//以下为程序控制段方法public void paint(Graphics g){if(x>getWidth()){x=-50;if(consumerandproducer.index>7){dd.suspend();}if(consumerandproducer.mark1.getText()=="消费进行中"){testing22.dd1.resume();}Component[] labels = consumerandproducer.jl5.getComponents ();((JLabel)labels[consumerandproducer.index++]).setIcon (icon);if(consumerandproducer.index==9){consumerandproducer.jlabel.setText("仓库已满,生产停止,请先消费!");}if(consumerandproducer.index!=9){consumerandproducer.jlabel.setText("生产状态下当前仓库产品数量为:"+consumerandproducer.index);}}super.paint(g);g.drawImage(icon1, x, y, jl1);repaint();}}class Thread2 extends Thread{public void run(){while(true){testing11.x+=25;try{Thread2.sleep(50);} catch (InterruptedException e){e.printStackTrace();}}}}class Thread3 extends Thread{private JFrame f;public Thread3(JFrame f){this.f=f;JButton jb1=new JButton("点击开始模拟");jb1.setBounds(2,370,150,40);f.add(jb1);jb1.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){if(consumerandproducer.index==0){testing22.dd1.start();testing11.dd.start();}if(consumerandproducer.index!=0){consumerandproducer.jlabel.setText("模拟进行中,请点击恢复模拟!");}}});JButton jb2=new JButton("暂停模拟");jb2.setBounds(2,412,150,40);f.add(jb2);jb2.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){consumerandproducer.jlabel.setText("模拟已暂停,需恢复模拟请点击“恢复模拟”或者生产、消费按钮");testing11.dd.suspend();testing22.dd1.suspend();}});JButton jb3=new JButton("恢复模拟");jb3.setBounds(2,456,150,40);f.add(jb3);jb3.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){//两个if消除Component数组越界问题if(consumerandproducer.index==9){consumerandproducer.index=consumerandproducer.index-1;}if(consumerandproducer.index==0){consumerandproducer.index=consumerandproducer.index+1;}testing11.dd.resume();testing22.dd1.resume();}});}}。
生产者消费者问题程序示例制作:PrinceJie 本程序由JAVA语言制作,能够基本实现生产者消费者问题的演示。
本程序的工作原理:生产者和消费者分别设定为3个。
生产者和消费者公用产品缓冲区。
当生产者生产一件产品,则该产品进入缓冲区队列;当消费者消费一件产品,则该产品离开缓冲区队列。
缓冲区队列设定为5个,假若生产者生产了5件产品,若又有生产者生产了一件产品,则无法进入缓冲区。
这样的话,生产者进入生产者阻塞队列,并且相应的生产者的按钮变为不可用,即不可再生产。
用以表示进程的阻塞态。
若此时消费者消费了一件产品,则生产者阻塞队列中的产品可以进入产品缓冲区队列,这样的话,刚才被阻塞的生产者进程被唤醒,在本程序中表现为:该生产者按钮变为可用。
以下是改程序的框架示例:具体实现方法见源程序。
以下是程序的源代码:/** Code By PriceJie, All Rights Reserved.* Code Version 1.0* Finished Date 2011/10/21* QQ: 1013406824* JDK Version:1.6.0* 本程序系生产者消费者问题的程序示例,可基本实现对该问题的描述。
* 由于程序的代码量和功能量都较少,易于测试,可以保证无BUG。
* 在NetBeans以及Eclipse环境下均运行通过。
* 本代码作者学习JAVA时日不长,算法并不健全,多处方法实现较为复杂,并不合理。
* 望各位高手指正。
**/import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.border.*;import java.util.LinkedList;/** 程序的主类,继承JFrame类,实现ActionListener端口。
利用多线程模拟“生产者——消费者”问题。
在“生产者——消费者”模型中,生产者Producer 负责生产数据,而消费者Consumer负责使用数据。
多个生产者线程会在同一时间运行,生产数据,并放到内存中一个共享的区域。
期间,多个消费者线程读取内存共享区,消费里面的数据。
模拟生产者-消费者问题的UNL图:
图3 生产者-消费者UML
图3为模拟生产者-消费者的UML图,Product类为生产者产生的产品类,Producer类为生产者,Consumer类为消费者,QueueMessage类用来存储多个生
产者产生产品以及提供多个消费者消费产品。
Test类来测试“生产者-消费者”模拟系统。
3、模拟生产者-消费者问题的程序清单
package imut.cstd.j09_2.shiyan3;
public class Product { //产品类
private String pname;
public String getPname(){
return pname;
}
public void setPname(String pname){
this.pname = pname;
}
}
package imut.cstd.j09_2.shiyan3;
import java.util.LinkedList;
public class QueueMessage { //共享区类
private static int num = 0;
private final static int MAX_num = 30;//上线商品
private LinkedList<Product>queue = new LinkedList<Product>();
public boolean isEmpty(){
return queue.isEmpty();
}
public synchronized Product get(){
Product temp = null;
if(queue.isEmpty()){
System.out.println(Thread.currentThread().getName()+"消费者"+":"+"目前没有可消费的商品!");
try{
this.wait();
}catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
else if(!queue.isEmpty()){
try {
num--;
temp = queue.poll();
this.wait();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName()+"消费者"+"\t消费的商品号:"+temp.getPname()+"\t目前商品的数量是:"+num);
}
this.notifyAll();
return temp;
}
public synchronized void add(Product temp){
if(num<MAX_num){
num++;
this.queue.add(temp);
System.out.println(Thread.currentThread().getName()+"生产者"+"\t产生的商品号:"+temp.getPname()+"\t目前商品的数量是:"+num);
}
else if(num>MAX_num){
System.out.println("生产的商品的数量已经满足:"+num+"生产者
"+Thread.currentThread().getName()+"产生的商品存不了了!");
try{
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notifyAll();
}
}
package imut.cstd.j09_2.shiyan3;
public class Producer implements Runnable{ //生产者类
private QueueMessage queue ;
public QueueMessage getQueue(){
r eturn queue;
}
public void setQueue(QueueMessage queue){
t his.queue = queue;
}
public synchronized void run() {
for(int i = 0;i<20;i++){
Product product = new Product();
product.setPname(Thread.currentThread().getName()+"--->"+(i+1)+"\ t");
queue.add(product);
try{
Thread.sleep(200);
}catch(InterruptedException e){
System.out.println(e.getMessage());
}catch(NullPointerException e){
System.out.println(e.getMessage());
}
}
}
}
package imut.cstd.j09_2.shiyan3;
public class Consumer implements Runnable{ //消费者类
private QueueMessage queue = null;
public QueueMessage getQueue(){
r eturn queue;
}
public void setQueue(QueueMessage queue){
t his.queue = queue;
}
public void run() {
for(int i = 0;i<20;i++){
queue.get();
try{
Thread.sleep(200);
}catch(InterruptedException e){
System.out.println(e.getMessage());
}catch(NullPointerException e){
System.out.println(e.getMessage());
}
}
}
}
package imut.cstd.j09_2.shiyan3;
public class Test {
public static void main(String[] args){ //测试类QueueMessage queue = new QueueMessage() ;
Producer producer = new Producer();
producer.setQueue(queue);
Consumer consumer = new Consumer();
consumer.setQueue(queue);
Thread p = new Thread(producer);
Thread p1 = new Thread(producer);
Thread p2 = new Thread(producer);
p.setName("p"); //定义了三个消费者
p1.setName("p1");
p2.setName("p2");
p.start();p1.start();p2.start();
Thread c = new Thread(consumer);
Thread c1 = new Thread(consumer);
c.setName("c"); c1.setName("c1");//定义了两个生产者 c.start();c1.start();
}
}。