生产者与消费者问题(Java)

合集下载

生产者消费者实验报告

生产者消费者实验报告

生产者消费者实验报告生产者消费者实验报告引言:生产者消费者模型是计算机科学中的一个经典问题,用于解决多线程并发访问共享资源的同步问题。

在本实验中,我们通过编写一个简单的Java程序来模拟生产者消费者模型,并观察其运行结果和效果。

一、实验背景生产者消费者模型是一种常见的并发模型,用于解决多线程访问共享资源时可能出现的数据竞争和同步问题。

在该模型中,生产者负责生产数据并将其放入共享缓冲区,而消费者则负责从缓冲区中取出数据进行消费。

为了确保生产者和消费者之间的同步与互斥,需要使用合适的同步机制,如信号量、互斥锁等。

二、实验目的本实验的主要目的是通过编写一个简单的生产者消费者程序,验证该模型在多线程环境下的正确性和效果。

我们将通过观察程序的输出结果和运行时间来评估其性能,并分析其中可能存在的问题和改进空间。

三、实验设计1. 编写生产者类和消费者类:我们首先定义了一个共享缓冲区,用于存储生产者生产的数据。

然后,我们编写了一个生产者类和一个消费者类,分别实现了生产者和消费者的逻辑。

在生产者类中,我们使用了一个循环来模拟生产者不断地生产数据,并将其放入缓冲区。

而在消费者类中,我们同样使用了一个循环来模拟消费者不断地从缓冲区中取出数据进行消费。

2. 同步机制的选择:为了保证生产者和消费者之间的同步与互斥,我们选择了信号量作为同步机制。

在生产者类中,我们使用一个信号量来控制缓冲区的可用空间,当缓冲区已满时,生产者将等待,直到有可用空间。

而在消费者类中,我们同样使用一个信号量来控制缓冲区的可用数据,当缓冲区为空时,消费者将等待,直到有可用数据。

3. 实验参数的设置:为了模拟真实的生产者消费者场景,我们设置了以下参数:- 缓冲区大小:10- 生产者数量:3- 每个生产者生产的数据量:1000- 消费者数量:2四、实验结果与分析在运行实验程序后,我们观察到以下结果:1. 生产者和消费者之间的同步与互斥得到了有效保证,生产者在缓冲区已满时会等待,直到有可用空间;消费者在缓冲区为空时会等待,直到有可用数据。

操作系统生产者消费者问题实验报告

操作系统生产者消费者问题实验报告

实验报告二实验名称:一、生产者-消费者问题的多线程解决方案二、设计一个执行矩阵乘法的多线程程序日期:2015-10-22 班级:13级计科学号:姓名:一、实验目的1.掌握线程的同步与互斥2.掌握生产者消费者的实现问题3.掌握多线程的编程方法4.掌握矩阵乘法的基本计算原理以及实现二、实验内容1.生产者-消费者问题的多线程解决方案2.设计一个执行矩阵乘法的多线程程序三、项目要求与分析1.请查阅资料,掌握线程创建的相关知识以及矩阵乘法的相关知识,了解java语言程序编写的相关知识2.理解线程的实验步骤在本次试验中,以“生产者-消费者”模型为依据,提供了一个多线程的“生产者-消费者”实例,编写java代码调试运行结果,得出相应的结论。

理解矩阵乘法的实验步骤四、具体实现1.生产者-消费者实例(1)创建一个缓冲信息发送接收通道接口,并创建邮箱盒子类实现,主要代码如下://通道接口public interface Channelpublic abstract void send(Object item);public abstract Object receive();}//实现接口public class MessageQueue implements Channel{private Vector queue;public MessageQueue(){queue=new Vector();}public void send(Object item){queue.addElement(ite m);}public Object receive(){if(queue.size()==0)return null;elsereturn queue.remove(0);}}(2)创建一个工厂多线程类(启动生产者和消费者),并且添加main函数进行测试,主要代码如下://工厂类与主方法public class Factory{public Factory(){Channel mailBox=new MessageQueue();Thread producerThread=new Thread(newProducer(mailBox));Thread consumerThread=new Thread(newConsumer(mailBox));producerThread.start();consumerThread.start();}public static void main(String[] args)Factory server=new Factory();}(3)创建一个线程睡眠类,用于测试,主要代码如下:public class SleepUtilities{public static void nap(){nap(NAP_TIME);}public static void nap(int duration){int sleeptime = (int)(NAP_TIME * Math.random());try{ Thread.sleep(sleeptime*1000); }catch (InterruptedException e) {}}private static final int NAP_TIME = 5;(4)创建生产者类实现Runnable,主要代码如下:public class Producer implements Runnable{private Channel mbox;public Producer(Channel mbox){this.mbox=mbox;}public void run(){Date message;while(true){SleepUtilities.nap();message=new Date();System.out.println("Producer produced "+message);mbox.send(message);}}}(5)创建消费者类实现Runnable,主要代码如下:public class Consumer implements Runnable{private Channel mbox;public Consumer(Channel mbox){this.mbox=mbox;}public void run(){Date message;while(true){SleepUtilities.nap();message=(Date)mbox.receive();if(message!=null)System.out.println("Consumer consumed "+message);}}}(6)调试程序,运行结果:2.矩阵乘法实例(1)初始化矩阵(便于观察,这里使用随机数生成矩阵),主要初始化代码如下matrix1 = new int[m][k];matrix2 = new int[k][n];matrix3 = new int[m][n];//随机初始化矩阵a,bfillRandom(matrix1);fillRandom(matrix2);static void fillRandom(int[][] x){for (int i=0; i<x.length; i++){for(int j=0; j<x[i].length; j++){//每个元素设置为0到99的随机自然数x[i][j] = (int) (Math.random() * 100);}}}(2)打印输出矩阵函数,主要代码如下:static void printMatrix(int[][] x){for (int i=0; i<x.length; i++){for(int j=0; j<x[i].length; j++){System.out.print(x[i][j]+" ");}System.out.println("");}System.out.println("");}(3)创建多线程类,并实现Runnable接口同步对矩阵进行分行计算,主要代码如下://创建线程,数量 <= 4for(int i=0; i<4; i++){if(index < m){Thread t = new Thread(new MyThread());t.start();}else{break;}synchronized static int getTask(){if(index < m){return index++;}return -1;}}class MyThread implements Runnable{int task;//@Overridepublic void run(){MultiThreadMatrix.threadCount++;while( (task = MultiThreadMatrix.getTask()) != -1 ) {System.out.println("进程:"+Thread.currentThread().getName()+"\t开始计算第"+(task+1)+"行");for(int i=0; i<MultiThreadMatrix.n; i++) {for(int j=0; j<MultiThreadMatrix.k; j++) {MultiThreadMatrix.matrix3[task][i] +=MultiThreadMatrix.matrix1[task][j] *MultiThreadMatrix.matrix2[j][i];}}}MultiThreadMatrix.threadCount--;}(4)通过不断改变矩阵大小,线程数目,,调试程序,运行结果:五、所遇问题与解决方法1.在生产者-消费者多线程试验中,刚开始没有考虑到使用线程睡眠,运行结果速度之快,没法观看数据变化,后面定义了睡眠控制,使得问题得以解决2.在多线程矩阵开发实验中,刚开始定义矩阵太小,测试结果不太明显,后面通过把矩阵改大,并且线程数目不断变化使得结果明显。

生产者与消费者问题

生产者与消费者问题

⽣产者与消费者问题⽣产者与消费者问题是Java多线程中⼀道⾮常经典的问题,问题如下: ⽣产者与消费者问题也称缓存问题,⽣产者与消费者即Java 中的线程,⽣产者与消费者问题即⽣产者⽣产⼀定数量的线程放⼊缓存区中,供消费者消费者消费,在消费和⽣产的过程中,如果⽣产者⽣产的产品超过了缓存区的上限则停⽌⽣产,等待消费者消费,如果缓存区的产品被消费完,消费者则停⽌消费,等待⽣产者⽣产 ⾸先,我们来看题⽬,从题⽬中我们⼀个可以抽取出⼏个实体类呢?答案是4个 Consumer(消费者),Producer(⽣产者),Product(产品),WareHouse(缓冲区,也叫仓库),于是项⽬结构如下,main 为测试类产品类package ProducersAndConsumers;//产品public class Product {//产品需要⼀个id 来表明产品的唯⼀性private Integer productId;//id直接由构造⽅法传⼊public Product(Integer productId) {this.productId = productId;}public Integer getProductId() {return productId;}@Overridepublic String toString() {return "Product{" +"productId=" + productId +'}';}}仓库package ProducersAndConsumers;import java.util.LinkedList;//仓库类public class WareHouse {//仓库容量,我们设置为10个private final int max = 10;//仓库基础的数量private final int base = 0;//我们设置⼀个集合来存放⽣产的产品,由于我们需要⼀个可以弹出最后⼀个产品的⽅法,所以我们在这⾥使⽤LinkedListprivate LinkedList<Product> products = new LinkedList<>();//⽣产⽅法public synchronized void push(Product product) {//判断是否有空间存放产品while(max==products.size()){try{System.out.println("仓库已满,消费者快来消费"+Thread.currentThread().getName()+"停⽌⽣产");//仓库满后停⽌当前线程this.wait();}catch (Exception ex){ex.printStackTrace();}}//⽣产商品products.addLast(product);System.out.println(Thread.currentThread().getName()+"⽣产了⼀个产品:"+product.getProductId()+"号");try{//等待1秒,⽅⾯我们观察Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}notifyAll();}//消费⽅法public synchronized void pop() {//判断是否有产品while (products.size()==base){try{System.out.println("仓库空了,⽣产者快点⽣产"+Thread.currentThread().getName()+"停⽌消费");//仓库空后停⽌当前线程this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费商品System.out.println(Thread.currentThread().getName()+"消费了⼀个产品:"+products.getLast().getProductId()+"号"); products.removeLast();try{//等待1秒,⽅⾯我们观察Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}notifyAll();}}⽣产者package ProducersAndConsumers;//⽣产者public class Producer implements Runnable {//⽣产产品的idprivate int count = 0;//仓库private WareHouse wareHouse;//⽣产者和消费者都是⽤同⼀个仓库,所以我们只要声明⼀个仓库,在由构造⽅法传⼊即可public Producer(WareHouse wareHouse) {this.wareHouse = wareHouse;}//⽣产⽅法@Overridepublic void run() {while (true){Product product = new Product(count);wareHouse.push(product);// 产品id不可重复,所以我们使⽤⾃增策略count++;}}}消费者package ProducersAndConsumers;public class Consumer implements Runnable{//仓库private WareHouse wareHouse;//⽣产者和消费者都是⽤同⼀个仓库,所以我们只要声明⼀个仓库,在由构造⽅法传⼊即可public Consumer(WareHouse wareHouse) {this.wareHouse = wareHouse;}//消费⽅法@Overridepublic void run() {while (true){wareHouse.pop();}}}最后测试类package ProducersAndConsumers;//测试类public class Main {public static void main(String[] args) {WareHouse wareHouse = new WareHouse();Producer producer = new Producer(wareHouse);Consumer consumer = new Consumer(wareHouse); Thread producerT = new Thread(producer,"⽣产者"); Thread consumerT = new Thread(consumer,"消费者"); producerT.start();consumerT.start();}}。

操作系统中的经典问题——生产者消费者问题(两种方式实现)

操作系统中的经典问题——生产者消费者问题(两种方式实现)

操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)1、问题引⼊:什么是⽣产者消费者问题?⽣产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是⼀个多线程同步问题的经典案例。

该问题描述了共享固定⼤⼩缓冲区的两个线程——即所谓的“⽣产者”和“消费者”——在实际运⾏时会发⽣的问题。

⽣产者的主要作⽤是⽣成⼀定量的数据放到缓冲区中,然后重复此过程。

与此同时,消费者也在缓冲区消耗这些数据。

该问题的关键就是要保证⽣产者不会在缓冲区满时加⼊数据,消费者也不会在缓冲区中空时消耗数据。

.要解决该问题,就必须让⽣产者在缓冲区满时休眠(要么⼲脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,⽣产者才能被唤醒,开始往缓冲区添加数据。

同样,也可以让消费者在缓冲区空时进⼊休眠,等到⽣产者往缓冲区添加数据之后,再唤醒消费者。

通常采⽤进程间通信的⽅法解决该问题。

如果解决⽅法不够完善,则容易出现死锁的情况。

出现死锁时,两个线程都会陷⼊休眠,等待对⽅唤醒⾃⼰。

该问题也能被推⼴到多个⽣产者和消费者的情形。

2、问题分析该问题需要注意的⼏点:1. 在缓冲区为空时,消费者不能再进⾏消费2. 在缓冲区为满时,⽣产者不能再进⾏⽣产3. 在⼀个线程进⾏⽣产或消费时,其余线程不能再进⾏⽣产或消费等操作,即保持线程间的同步4. 注意条件变量与互斥锁的顺序由于前两点原因,因此需要保持线程间的同步,即⼀个线程消费(或⽣产)完,其他线程才能进⾏竞争CPU,获得消费(或⽣产)的机会。

对于这⼀点,可以使⽤条件变量进⾏线程间的同步:⽣产者线程在product之前,需要wait直⾄获取⾃⼰所需的信号量之后,才会进⾏product的操作;同样,对于消费者线程,在consume之前需要wait直到没有线程在访问共享区(缓冲区),再进⾏consume的操作,之后再解锁并唤醒其他可⽤阻塞线程。

利用JAVA多线程并发机制解决生产者—消费者问题

利用JAVA多线程并发机制解决生产者—消费者问题
Ch n Yl e
A b t a t T e p p r a aye d d srb s te c mpiae rc s fmut t e d d J s r c : h a e n lz s a ecie h o l td p o es o li hra e AVA y c rnz t n me h ns a d n c — sn h o iai c a im n o
21 车2月 O0
电 脑 学 习
第1 期
利 用 J V 多线程 并发机制解 决生产者一 消费者 问题 A A
陈 益
摘 要 : 本文分析并描述 了J V A A多线程并发过程 中的同步机制及消息通信机制的基本原理 . 探讨如何运用多线程同步机制
和 消 息 互 通 机 制切 实 解 决 生 产 者 和 消费 者 之 间 的问 题 。
T ra h d类提供 了各种 与线 程有关 的方法 ,方 便 .本 文 将 采 用 继 承 T ra 来 实 现 多 h d类 e
线程技术 。但是在程序中 , 所有线程共 享同一 内存空 间, 两 个或多个线程可能 同时访 问同一变量或运行 同一对 象的同
Jv aa语言和 Jv 虚拟机提供 了完全 意义上的多线程支 aa 持 ,其 内置语言 级的多线程机制让用户更 方便地实现多个 并行程序 的开发 ,从 语言级上提供各个线 程问协调工作 的 调度能力 , 降低并发程序设计的难度 。在 Jv aa中, 多线程的
建 立 有 两 种 方 法 : 继 承 T ra hed类 和 实 现 R na l 口 。 un be接
te b sc p icpe fme sg o h a i rn ilso sa e c mmu c to c a im, x lr h o ue mut tra y c rnzto l h - i n ain me h s e po ̄ n wo t s li he d s ho ain l - n i  ̄c a im ns a d me sg x h n e me h ns ta ud e e t ey sle te p be ewe n po u esa o s mes n sa e e c a g c a im h twol f ci l ov h r lms b t e rd c r nd c n u r. v o litra e Ke wo d Mut-he d d y r: S n ho iain y c r nzt o C nt o cm ̄n e c P o u e rd c r C nu r o s me

操作系统生产者-消费者问题(PV操作)(Java实现)

操作系统生产者-消费者问题(PV操作)(Java实现)

操作系统⽣产者-消费者问题(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();//当⽣产者或消费者向缓冲区放⼊或取出⼀个产品时,向其他等待的线程发出通知,同时释放锁,使⾃⼰处于等待状态,让其它线程执⾏。

操作系统实验报告 经典的生产者—消费者问题

操作系统实验报告  经典的生产者—消费者问题

实验二经典的生产者—消费者问题一、目的实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。

二、实验内容及要求编制生产者—消费者算法,模拟一个生产者、一个消费者,共享一个缓冲池的情形。

1、实现对经典的生产者—消费者问题的模拟,以便更好的理解此经典进程同步问题。

生产者-消费者问题是典型的PV操作问题,假设系统中有一个比较大的缓冲池,生产者的任务是只要缓冲池未满就可以将生产出的产品放入其中,而消费者的任务是只要缓冲池未空就可以从缓冲池中拿走产品。

缓冲池被占用时,任何进程都不能访问。

2、每一个生产者都要把自己生产的产品放入缓冲池,每个消费者从缓冲池中取走产品消费。

在这种情况下,生产者消费者进程同步,因为只有通过互通消息才知道是否能存入产品或者取走产品。

他们之间也存在互斥,即生产者消费者必须互斥访问缓冲池,即不能有两个以上的进程同时进行。

三、生产者和消费者原理分析在同一个进程地址空间内执行两个线程。

生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。

消费者线程从缓冲区中获得物品,然后释放缓冲区。

当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放一个空缓冲区。

当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻挡,直到新的物品被生产出来。

四、生产者与消费者功能描述:生产者功能描述:在同一个进程地址空间内执行两个线程。

生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。

当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。

消费者功能描述:消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

五、实验环境操作系统环境:Windows系统。

编程语言:C#。

六、生产者与消费者的思路和设计1、程序流程图(1) 生产者.(2) 消费者2、主要程序代码//初始化变量private void Form1_Load(object sender, EventArgs e){mutex = 1; //互斥信号量full = 0; //缓冲池中满缓冲区的数量empty = 5;//缓冲池中空缓冲区的数量count1 = 0;//生产的产品数目i = 0;lb_mutex.Text = "1";lb_full.Text = "0";lb_empty.Text = "5";}//消费者从缓冲区中消费一个产品private void consumer_Click(object sender, EventArgs e){if (full > 0){ //消费者已进入互斥临界区if (mutex == 1) //申请进入临界区{mutex = 0; //消费者已进入互斥临界区lb_mutex.Text = "0";timer_consumer.Enabled = true;//启动消费者消费缓冲区产品}else{MessageBox.Show("缓冲区被占用,请等待。

操作系统实验报告三大问题之生产者与消费者问题

操作系统实验报告三大问题之生产者与消费者问题

计算机操作系统实验报告题目三大经典问题之生产者与消费者问题一、课程设计的性质与任务1、加深对并发协作进程同步与互斥概念的理解。

通过编写程序实现进程同步和互斥,使学生掌握有关进程(线程)同步与互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥等有关的内容。

2、掌握进程和线程的概念,进程(线程)的控制原语或系统调用的使用。

3、了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。

学习使用Windows2000/XP中基本的同步对象,掌握相应的API函数。

4、培养学生能够独立进行知识综合,独立开发较大程序的能力。

5、培养提高学生软件开发能力和软件的调试技术。

6、培养学生开发大型程序的方法和相互合作的精神。

7、培养学生的创新意识。

8、培养学生的算法设计和算法分析能力。

9、培养学生对问题进行文字论述和文字表达的能力。

二、课程设计的内容及其要求在Windows?XP、Windows?2000等操作系统下,使用的VC、VB、Java或C等编程语言,采用进程(线程)同步和互斥的技术编写程序实现生产者消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程)同步和互斥的实际问题。

要求:(1)经调试后程序能够正常运行。

(2)采用多进程或多线程方式运行,体现了进程(线程)同步互斥的关系。

(3)程序界面美观。

三、实验原理本实验要求利用PV操作实现解决生产者——消费者问题中的同步问题。

此问题描述的是一群生产者进程在生产产品并将这些产品提供给消费者进程去消费,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区,消费者进程可从缓冲区中取走产品去消费,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品,也不允许生产者进程向一个已装满且尚未取出的缓冲区中投放产品,并且生产者消费者互斥使用缓冲区。

四、实验原理图五、算法实现(1)有一个生产者线程ProduceThread,有1个消费者进程CustomerThread;缓冲区为shareList。

生产者消费者问题

生产者消费者问题

⽣产者消费者问题⽣产者消费者问题背景在并发编程中,⽣产者消费者问题(producer/consumer)是⼀个经典的⽼⽣常谈的问题,有时也称为有界缓冲区问题。

问题的基本背景假设是:我们有⼀个固定⼤⼩的缓冲区,这个缓冲区分别有两种⼯作性质不同的线程去操作。

其中⼀种线程负责向缓冲区中写⼊数据,我们称之为⽣产者线程。

另⼀种线程则负责从缓冲区中拿取数据,并称之为消费者线程。

同时两种线程的写⼊和拿取⼯作要遵循⼀定的规则:1. 缓冲区未写满时,⽣产者线程可以向缓冲区中写⼊数据。

但是消费者线程不能从缓冲区中读取数据。

2. 缓冲区写满时,⽣产者线程不能向缓冲区中写⼊数据,消费者线程可以冲缓冲区中读取数据。

3. 不管是那种性质的线程,在操作缓冲区时,均不可出现并发安全问题。

分析可以得知,解决⽣产者消费者问题,其实就是要解决线程同步问题与共享资源互斥访问问题。

互斥问题的解决可以借助锁来实现,⽽线程同步则需借助信号量或其他⼯具来实现。

Java实现class FixedSizeBuffer{private static final int DEFAULT_BUFFER_SIZE = 1024;private final ReentrantLock lock = new ReentrantLock(); // 共享资源访问锁private final Condition isFull = lock.newCondition(); // buffer是否已满private final Condition isEmpty = lock.newCondition(); // buffer是否还空着private final int size; // buffer的⼤⼩private final byte[] buffer; // bufferprivate int cursor; // 写⼊游标public FixedSizeBuffer(){this(DEFAULT_BUFFER_SIZE);}public FixedSizeBuffer(int size){if (size <= 0) throw new IllegalArgumentException();this.size = size;this.buffer = new byte[size];cursor = -1;}/*** 向buffer中写⼊⼀个字节的数据* @param content 数据内容* @throws InterruptedException 中断异常*/public void putByte(byte content) throws InterruptedException{/*由于要对共享资源buffer进⾏访问,所以要加锁。

两种解决生产者—消费者问题的Java实现模型

两种解决生产者—消费者问题的Java实现模型

并 且在 Jv . aa中 可采 用 sn ho i d或 O jc 类 的 方 y crnz e b t e 法 w i )n ty )r ty l ) 实现 多线程 同步 。 at ,oi ( ,oi Al 来 ( f  ̄f ( Jv 线茬 同 步机 制 的实 现是 基 于管 程 ( n. aa多 Mo i
() 2 生产 者一 费者 问题 的解 决模型 与 I a实现 消 a v


在下 面 的 Jv a a应用 程序 中 .生 产者线 程 向缓 冲
o OENC PT , MDR O UE 6 M R
维普资讯
实 践 与 经 验
区中写数据 , 费者从缓 冲 区中读数 据 , 消 这样 , 在这个 程序 中同时运行 的多个线 程竞 争 同一 个缓 冲区 资源 。 类 Po ue 是 生 产者 模 型 , 中的 rn ) rd cr 其 u f 方法 中定义 了生产者线 程所做 的操作 . 环地将 生产 的“ 品” 循 产 放 入缓 冲区 中 , 每次 生产完 后 。 用 s e f 方 法睡 眠一 调 l p) e 段随机时 间 , 以给其他线 程执 行的机会 。类 C nu r o sme
维普资讯
安 践 与 经 验
范 容 . 胡 则辉
( 杭州 师范学 院信息 工程 学院 . 杭州 3 0 1 ) 10 8

要 : 文 以Jv 的 多线程机 制为技 术手段 , 拟 了经典 的生 产者 消费者 问题 , 本 aa 模 解决 了此 问题 中 的 同步 问题 。
产 者 p 生产 的产 品就 可 以投入 缓 冲 区 ; 似地 , i 类 只要
现 代 计


生产者消费者问题

生产者消费者问题
down(&mutex); // 进入临界区
insert_item(item); // 将新数据放入缓冲区
up(&mutex); // 离开临界区
if (count == N -1) // 缓冲区有空槽
{ // 唤醒生产者
consumer_item(item); // 处理数据项
}
}
该解决方案使用了三个信号量:一个为 full,用来记录充满的缓冲槽的数目,一个为 empty,记录空的缓冲槽总数,一个为 mutex,用来确保生产者和消费者不会同时访问缓冲区。mutex 的初始值为 1,供两个或者多个进程使用的信号量,保证同一个时刻只有一个进程可以进入临界区,称为二元信号量(binary semaphore)。如果每一个进程在进入临界区前都执行一个 down(...),在刚刚退出临界区时执行一个 up(...),就能够实现互斥。
生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。
// 缓冲区大小
#define N 100
int count = 0; // 跟踪缓冲区的记录数
/* 生产者进程 */
void procedure(void)

java并发编程 例子

java并发编程 例子

java并发编程例子Java并发编程是指在Java程序中使用多线程实现并发操作的一种编程方式。

并发编程可以提高程序的执行效率和响应速度,但同时也带来了一些潜在的问题,如线程安全、死锁等。

下面是一些使用Java并发编程的例子。

1. 生产者消费者模型生产者消费者模型是一种常见的并发编程模式,用于解决生产者和消费者之间的数据共享和同步问题。

在Java中,可以使用多线程和线程间通信机制来实现生产者消费者模型。

例如,一个线程作为生产者生成产品,另一个线程作为消费者消费产品,它们通过共享的缓冲区进行通信。

2. 线程池线程池是一种用于管理线程的机制,它可以重用线程,减少线程的创建和销毁开销,提高系统的性能和资源利用率。

在Java中,可以使用java.util.concurrent包中的ThreadPoolExecutor类来创建和管理线程池。

通过线程池,可以快速创建大量的线程,并且控制线程的数量和执行顺序。

3. 互斥锁互斥锁是一种用于保护共享资源的机制,它可以确保在同一时间只有一个线程可以访问共享资源,避免竞争条件和数据不一致问题。

在Java中,可以使用synchronized关键字或Lock接口来实现互斥锁。

通过互斥锁,可以保证线程的安全性,避免数据的并发修改。

4. 并发集合并发集合是一种用于在多线程环境下进行数据共享和同步的数据结构,它提供了线程安全的操作和高效的性能。

在Java中,可以使用java.util.concurrent包中的ConcurrentHashMap、ConcurrentLinkedQueue等类来实现并发集合。

通过并发集合,可以实现多线程之间的数据共享和同步。

5. CountDownLatchCountDownLatch是一种用于线程间通信的同步工具,它可以使一个或多个线程等待其他线程的完成。

在Java中,可以使用java.util.concurrent包中的CountDownLatch类来实现CountDownLatch。

生产者消费者问题总结

生产者消费者问题总结

⽣产者消费者问题总结⽣产者-消费者算是并发编程中常见的问题。

依靠缓冲区我们可以实现⽣产者与消费者之间的解耦。

⽣产者只管往缓冲区⾥⾯放东西,消费者只管往缓冲区⾥⾯拿东西。

这样我们避免⽣产者想要交付数据给消费者,但消费者此时还⽆法接受数据这样的情况发⽣。

wait notify这个问题其实就是线程间的通讯,所以要注意的是不能同时读写。

⽣产者在缓冲区满的时候不⽣产,等待;消费者在缓冲区为空的时候不消费,等待。

⽐较经典的做法是wait和notify。

⽣产者线程执⾏15次set操作public class Producer implements Runnable{private Channel channel;public Producer(Channel channel) {this.channel = channel;}@Overridepublic void run() {for(int i=0;i<15;i++){channel.set(Thread.currentThread().getName()+" "+i);}}}消费者线程执⾏10次get操作public class Consumer implements Runnable {private Channel channel;public Consumer(Channel channel) {this.channel = channel;}@Overridepublic void run() {for(int i=0;i<10;i++){System.out.println("Consumer "+Thread.currentThread().getName()+" get "+channel.get());}}}现在定义Channel类,并创建两个⽣产者线程和三个消费者线程public class Channel {private List<String> buffer=new ArrayList<>();private final int MAX_SIZE=10;public synchronized String get(){while (buffer.size()==0){//不要⽤if,醒来了也要再次判断try {wait();} catch (InterruptedException e) {e.printStackTrace();}}String str=buffer.remove(0);notifyAll();return str;}public synchronized void set(String str){while (buffer.size()==MAX_SIZE){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}buffer.add(str);notifyAll();}public static void main(String[] args) {Channel channel=new Channel();Producer producer=new Producer(channel);Consumer consumer=new Consumer(channel);for(int i=0;i<2;i++){new Thread(producer).start();}for (int i=0;i<3;i++){new Thread(consumer).start();}}}使⽤notifyAll⽽不是notify的原因是,notify有可能出现多次唤醒同类的情况,造成“假死”。

Java线程实现Redis任务队列(生产者消费者)

Java线程实现Redis任务队列(生产者消费者)

Java线程实现Redis任务队列(生产者消费者)Redis是一种开源的高性能键值存储数据库,常用于缓存、消息队列和任务队列等场景。

在Java中,我们可以利用Redis实现一个简单的任务队列,使用多线程来实现生产者消费者模式。

在Java中,可以使用Jedis库与Redis进行交互。

首先,我们需要引入Jedis库的依赖,例如通过Maven引入以下依赖项:```xml<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency>```接下来,我们可以创建一个生产者类和一个消费者类来实现任务队列。

```javaimport redis.clients.jedis.Jedis;public class Producer implements Runnableprivate Jedis jedis;private String queueName;this.jedis = jedis;this.queueName = queueName;}public void rufor (int i = 0; i < 10; i++)String task = "Task " + i;jedis.rpush(queueName, task);System.out.println("Produced task: " + task); tryThread.sleep(1000);} catch (InterruptedException e)e.printStackTrace(;}}}public class Consumer implements Runnable private Jedis jedis;private String queueName;this.jedis = jedis;this.queueName = queueName;}public void ruwhile (true)List<String> tasks = jedis.blpop(0, queueName); String task = tasks.get(1);System.out.println("Consumed task: " + task); tryThread.sleep(2000);} catch (InterruptedException e)e.printStackTrace(;}}}```在生产者类中,我们使用`jedis.rpush(queueName, task)`方法将任务推送到Redis的列表中。

操作系统生产者消费者缓冲池与区的问题

操作系统生产者消费者缓冲池与区的问题

一个生产者一个消费者对应一个缓冲区;源程序:我用的是java语言。

import ng.Math;public class AProBuffCon //加互斥锁的缓冲区{private int value; //共享变量private boolean isEmpty=true; //value是否为空的信号量public synchronized void put(int i) //同步方法{while (!isEmpty) //当value不空时,等待try{this.wait(); //使调用该方法的当前线程等待,即阻塞自己}catch(InterruptedException e) {}value = i; //当value空时,value获得值System.out.println(Thread.currentThread().getName()+" Producer put : "+value);isEmpty = false; //设置value为不空状态notifyAll(); //唤醒其他所有等待线程}public synchronized int get() //同步方法{while (isEmpty) //当value空时,等待try{this.wait();}catch(InterruptedException e) {}isEmpty = true; //设置value为空状态,并返回值notifyAll(); //唤醒其他所有等待线程return value;}public static void main (String args[]){AProBuffCon buffer = new AProBuffCon();(new Producered(buffer)).start(); //构造两个生产者线程和两个消费者线程(new Consumered(buffer)).start();}}class Producered extends Thread //生产者{private AProBuffCon buffer;public Producered(AProBuffCon buffer){this.buffer = buffer;}public void run( ){// for (int i=1; i<=10; i++)// {int j=(int)(Math.random()*10);buffer.put(j);// }}}class Consumered extends Thread //消费者{private AProBuffCon buffer;public Consumered(AProBuffCon buffer){this.buffer = buffer ;}public void run(){// for (int i=1; i<=10; i++) //消费者从缓冲区中取数System.out.println("\t\t\t\t"+Thread.currentThread().getName()+" Consumer get : "+buffer.get());}}说明:都是先生产在消费。

reentrantlock的使用案例

reentrantlock的使用案例

reentrantlock的使用案例【实用版】目录1.ReentrantLock 简介2.ReentrantLock 使用案例一:银行账户取款3.ReentrantLock 使用案例二:线程安全的集合类4.ReentrantLock 使用案例三:生产者与消费者问题5.ReentrantLock 使用案例总结正文一、ReentrantLock 简介ReentrantLock 是 Java 并发编程中的一种重要同步工具,它允许线程在已经获取到锁的情况下再次获取锁,这种特性在很多场景下可以避免死锁的发生。

与 synchronized 关键字和原子变量相比,ReentrantLock 提供了更加灵活的锁控制方式,可以更好地满足多线程编程的需求。

二、ReentrantLock 使用案例一:银行账户取款在银行账户取款的场景中,为了保证账户的安全性,需要对账户的操作进行同步。

可以使用 ReentrantLock 来实现这一功能。

以下是一个简单的示例:```javaimport java.util.concurrent.locks.ReentrantLock;public class BankAccount {private double balance;private final ReentrantLock lock = new ReentrantLock();public void deposit(double amount) { lock.lock();try {balance += amount;} finally {lock.unlock();}}public void withdraw(double amount) { lock.lock();try {balance -= amount;} finally {lock.unlock();}}public double getBalance() {lock.lock();try {return balance;} finally {lock.unlock();}}}```三、ReentrantLock 使用案例二:线程安全的集合类在实现线程安全的集合类时,可以使用 ReentrantLock 来保证集合的同步。

Java实现生产者消费者问题与读者写者问题

Java实现生产者消费者问题与读者写者问题

Java实现⽣产者消费者问题与读者写者问题摘要: Java实现⽣产者消费者问题与读者写者问题1、⽣产者消费者问题⽣产者消费者问题是研究多线程程序时绕不开的经典问题之⼀,它描述是有⼀块缓冲区作为仓库,⽣产者可以将产品放⼊仓库,消费者则可以从仓库中取⾛产品。

解决⽣产者/消费者问题的⽅法可分为两类:(1)采⽤某种机制保护⽣产者和消费者之间的同步;(2)在⽣产者和消费者之间建⽴⼀个管道。

第⼀种⽅式有较⾼的效率,并且易于实现,代码的可控制性较好,属于常⽤的模式。

第⼆种管道缓冲区不易控制,被传输数据对象不易于封装等,实⽤性不强。

同步问题核⼼在于:如何保证同⼀资源被多个线程并发访问时的完整性。

常⽤的同步⽅法是采⽤信号或加锁机制,保证资源在任意时刻⾄多被⼀个线程访问。

Java语⾔在多线程编程上实现了完全对象化,提供了对同步机制的良好⽀持。

在Java中⼀共有五种⽅法⽀持同步,其中前四个是同步⽅法,⼀个是管道⽅法。

wait() / notify()⽅法await() / signal()⽅法BlockingQueue阻塞队列⽅法Semaphore⽅法PipedInputStream / PipedOutputStream1.1 wait() / notify()⽅法wait() / nofity()⽅法是基类Object的两个⽅法,也就意味着所有Java类都会拥有这两个⽅法,这样,我们就可以为任何对象实现同步机制。

wait()⽅法:当缓冲区已满/空时,⽣产者/消费者线程停⽌⾃⼰的执⾏,放弃锁,使⾃⼰处于等等状态,让其他线程执⾏。

notify()⽅法:当⽣产者/消费者向缓冲区放⼊/取出⼀个产品时,向其他等待的线程发出可执⾏的通知,同时放弃锁,使⾃⼰处于等待状态。

各起了4个⽣产者,4个消费者package test;public class Hosee {private static Integer count = 0;private final Integer FULL = 10;private static String LOCK = "LOCK";class Producer implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}synchronized (LOCK) {while (count == FULL) {try {LOCK.wait();} catch (Exception e) {e.printStackTrace();}}count++;System.out.println(Thread.currentThread().getName() + "⽣产者⽣产,⽬前总共有" + count);LOCK.notifyAll();}}}}class Consumer implements Runnable {@Overridepublic void run() {Thread.sleep(3000);} catch (InterruptedException e1) {e1.printStackTrace();}synchronized (LOCK) {while (count == 0) {try {LOCK.wait();} catch (Exception e) {}}count--;System.out.println(Thread.currentThread().getName() + "消费者消费,⽬前总共有" + count);LOCK.notifyAll();}}}}public static void main(String[] args) throws Exception {Hosee hosee = new Hosee();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();}}(需要注意的是,⽤什么加锁就⽤什么notify和wait,实例中使⽤的是LOCK)部分打印结果:由于⽣产者和消费者说明⼀致,所以最多都是在2左右,当减少⼀个消费者时,则会加到10。

生产者和消费者问题

生产者和消费者问题

班级姓名:学号:成绩:实验名称: 生产者和消费者问题1.实验目的:“生产者消费者”问题是一个著名的同时性编程问题的集合。

通过编写经典的“生产者消费者”问题的实验,读者可以进一步熟悉Linux 中多线程编程,并且掌握用信号量处理线程间的同步互斥问题。

2.实验内容:“生产者消费者”问题描述如下。

有一个有限缓冲区和两个线程:生产者和消费者。

他们分别把产品放入缓冲区和从缓冲区中拿走产品。

当一个生产者在缓冲区满时必须等待,当一个消费者在缓冲区空时也必须等待。

它们之间的关系如下图所示:这里要求用有名管道来模拟有限缓冲区,用信号量来解决生产者消费者问题中的同步和互斥问题。

3.实验方法:(1)使用信号量解决(2)思考使用条件变量解决4.实验过程(1)信号量的考虑这里使用3个信号量,其中两个信号量avail和full分别用于解决生产者和消费者线程之间的同步问题,mutex是用于这两个线程之间的互斥问题。

其中avail初始化为N(有界缓冲区的空单元数),mutex 初始化为1,full初始化为0。

/*product.c*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <errno.h>#include <sys/ipc.h>#include <semaphore.h>#include <fcntl.h>#define FIFO "myfifo"#define N 5int lock_var;time_t end_time;char buf_r[100];sem_t mutex,full,avail;int fd;void pthread1(void *arg);void pthread2(void *arg);int main(int argc, char *argv[]){pthread_t id1,id2;pthread_t mon_th_id;int ret;end_time = time(NULL)+30;/*创建有名管道*/if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf("cannot create fifoserver\n");printf("Preparing for reading bytes...\n");memset(buf_r,0,sizeof(buf_r));/*打开管道*/fd=open(FIFO,O_RDWR|O_NONBLOCK,0);if(fd==-1){perror("open");exit(1);}/*初始化互斥信号量为1*/ret=sem_init(&mutex,0,1);/*初始化avail信号量为N*/ret=sem_init(&avail,0,N);/*初始化full信号量为0*/ret=sem_init(&full,0,0);if(ret!=0){perror("sem_init");}/*创建两个线程*/ret=pthread_create(&id1,NULL,(void *)productor, NULL); if(ret!=0)perror("pthread cread1");ret=pthread_create(&id2,NULL,(void *)consumer, NULL); if(ret!=0)perror("pthread cread2");pthread_join(id1,NULL);pthread_join(id2,NULL);exit(0);}/*生产者线程*/void productor(void *arg){int i,nwrite;while(time(NULL) < end_time){/*P操作信号量avail和mutex*/sem_wait(&avail);sem_wait(&mutex);/*生产者写入数据*/if((nwrite=write(fd,"hello",5))==-1){if(errno==EAGAIN)printf("The FIFO has not been read yet.Please try later\n"); }elseprintf("write hello to the FIFO\n");/*V操作信号量full和mutex*/sem_post(&full);sem_post(&mutex);sleep(1);}}/*消费者线程*/void consumer(void *arg){int nolock=0;int ret,nread;while(time(NULL) < end_time){/*P操作信号量full和mutex*/sem_wait(&full);sem_wait(&mutex);memset(buf_r,0,sizeof(buf_r));if((nread=read(fd,buf_r,100))==-1){if(errno==EAGAIN)printf("no data yet\n");}printf("read %s from FIFO\n",buf_r);/*V操作信号量avail和mutex*/sem_post(&avail);sem_post(&mutex);sleep(1);}}(2)条件变量的考虑#include <stdio.h>#include <pthread.h>#define BUFFER_SIZE 4#define OVER (-1)struct producers//定义生产者条件变量结构{int buffer[BUFFER_SIZE];pthread_mutex_t lock;int readpos, writepos;pthread_cond_t notempty;pthread_cond_t notfull;};//初始化缓冲区void init(struct producers *b){pthread_mutex_init(&b->lock,NULL);pthread_cond_init(&b->notempty,NULL);pthread_cond_init(&b->notfull,NULL);b->readpos=0;b->writepos=0;}//在缓冲区存放一个整数void put(struct producers *b, int data){pthread_mutex_lock(&b->lock);//当缓冲区为满时等待while((b->writepos+1)%BUFFER_SIZE==b->readpos) {pthread_cond_wait(&b->notfull,&b->lock);}b->buffer[b->writepos]=data;b->writepos++;if(b->writepos>=BUFFER_SIZE) b->writepos=0;//发送当前缓冲区中有数据的信号pthread_cond_signal(&b->notempty);pthread_mutex_unlock(&b->lock);}int get(struct producers *b){int data;pthread_mutex_lock(&b->lock);while(b->writepos==b->readpos){pthread_cond_wait(&b->notempty,&b->lock); }data=b->buffer[b->readpos];b->readpos++;if(b->readpos>=BUFFER_SIZE) b->readpos=0; pthread_cond_signal(&b->notfull);pthread_mutex_unlock(&b->lock);return data;}struct producers buffer;void *producer(void *data){int n;for(n=0;n<10;n++){printf("Producer : %d-->\n",n);put(&buffer,n);}put(&buffer,OVER);return NULL;}void *consumer(void *data){int d;while(1){d=get(&buffer);if(d==OVER) break;printf("Consumer: --> %d\n",d);}return NULL;}int main(){pthread_t tha,thb;void *retval;init(&buffer);pthread_create(&tha,NULL,producer,0); pthread_create(&thb,NULL,consumer,0); pthread_join(tha,&retval);pthread_join(thb,&retval);return 0;}。

java pecs原则

java pecs原则

java pecs原则Java PECS原则是一种在泛型编程中常用的设计原则,可帮助开发人员更好地使用泛型类型。

PECS是一个缩写,它代表生产者( Producer)和消费者(Consumer)。

在Java PECS原则中,我们需要将泛型类型定义为生产者或消费者,并按照以下步骤处理:1. 确定我们的泛型类型是生产者还是消费者:在泛型类型中,我们可以使用通配符来定义泛型参数的类型。

例如,如果我们有一个列表,它只包含整数类型,那么我们可以定义泛型参数类型为List<? extends Integer>。

在该泛型定义中,通配符“?”代表我们不确定定义的具体类型是什么,但是它必须是Integer或者它的子类型。

这个泛型类型是生产者类型,因为它只能提供这个整数列表的元素,并且不会修改它们。

2. 确定我们的泛型类型是否需要进行可修改的操作:如果我们定义的泛型类型需要执行可修改的操作,则必须定义为消费者泛型类型。

例如,如果我们有一个列表,需要添加元素,我们可以定义泛型参数类型为List<? super Integer>,这个泛型类型是消费者类型,因为它需要接受Integer类型的元素来添加到列表中。

3. 在生产者泛型中使用extends,而不是使用super:在定义泛型参数类型时,需要根据是否为生产者或消费者进行选择。

对于生产者泛型类型,我们应该使用extends来定义它,因为我们只需要使用这个类型中的元素,而不需要对它们进行修改。

例如,我们可以定义一个通配符类型List<? extends Number>,它可以指定任何Number类型或其子类型的列表。

4. 在消费者泛型中使用super,而不是使用extends:为了定义一个消费者类型的泛型参数,我们必须使用super来定义它,因为我们需要执行添加元素的操作。

也就是说,我们需要告诉编译器这个泛型类型可以接受一个Number或其父类型的元素。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

package Table;
public class Message {
public static int id;
public String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
Message.id = id;
}
}
package Table;
import java.util.ArrayList;
import java.util.List;
public class Queue {
List<Message> queue = new ArrayList<Message>();
/** 队列中message对象的最大值,默认为10 */
int maxMessageNum = 10;
public synchronized void produce(Message message) {
/**synchronized为关键字,表示在任何一个线程要访问缓冲区时都会
检查有无其他线程访问此段内容,有的话则等待,无的话则直接访问**/
this.notifyAll();
while (queue.size() == maxMessageNum) {
System.out.println(Thread.currentThread().getName()
+ "the desk is full, and the chef want to relax");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.add(message);
System.out.println(Thread.currentThread().getName() + "the chef make a deal"
+ message.getContent() + ":" + getCount());
}
public synchronized void consume() {
this.notifyAll();
while (queue.size() == 0) {
System.out.println(Thread.currentThread().getName()
+ "the desk is empty, the consumer is complaining");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Message message = queue.get(0);
queue.remove(0);
System.out.println(Thread.currentThread().getName() + "the consumer takes away one deal"
+ message.getContent() + ": " + getCount());
}
public synchronized int getCount() {
return queue.size();
}
}
package Table;
public class Run {
public static void main(String args[]) {
Queue Q = new Queue();
Producer wQ1 = new Producer(Q);
Producer wQ2 = new Producer(Q);
Consumer rQ1 = new Consumer(Q);
Consumer rQ2 = new Consumer(Q);
Consumer rQ3 = new Consumer(Q);
Thread threadWQ1 = new Thread(wQ1, "thread-wQ1"); Thread threadWQ2 = new Thread(wQ2, "thread-wQ2");
Thread threadRQ1 = new Thread(rQ1, "thread-rQ1"); Thread threadRQ2 = new Thread(rQ2, "thread-rQ2"); Thread threadRQ3 = new Thread(rQ3, "thread-rQ3");
threadWQ1.start();
threadWQ2.start();
threadRQ1.start();
threadRQ2.start();
threadRQ3.start();
}
}
class Producer extends Thread {
private Queue queue;
Producer(Queue queue) {
this.queue = queue;
}
public void run() {
while (true) {
Message message = new Message();
message.setId(++Message.id);
message.setContent("food"+Message.id);
queue.produce(message);
try {
sleep(1000);
} catch (Exception e) {
}
}
}
}
class Consumer extends Thread { private Queue queue;
Consumer(Queue queue) {
this.queue = queue;
}
public void run() {
while (true) {
queue.consume();
try {
sleep(1000);
} catch (Exception e) {
}
}
}
}。

相关文档
最新文档