📄 源代码producer_consumer.java
字号:
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
public class Producer_Consumer extends Applet implements ActionListener
{
public static final int k=5;
public static final int SPEED=5000;
CBuffer bBuf; //the object of Buffer process
CConsumer cCons; //the object of Consumer process
CProducer pProd; //the object of Producer process这是三个进程,一定要注意,很关键
Panel pbutton;
private Button bStart=new Button();
private Button bPause=new Button();
private Button bEnd=new Button();
private Button bContinue=new Button();
GridBagConstraints cons;
CTrace1 trace1;
CTrace2 trace2; //动画步骤
CIntroCanvas introduce; //说明语句
CProducerCanvas pProdC;
CConsumerCanvas cConsC;
CBufferCanvas bBufC;//声明一些对象,在具体用时在进行创建
public void init()
{
GridBagLayout layout=new GridBagLayout();//利用GridBagLayout布局管理器
setLayout(layout);
resize(500,500);//显示大小
cons=new GridBagConstraints();
cons.anchor=GridBagConstraints.CENTER;
cons.weightx=300;
cons.weighty=300;
pbutton= new Panel(); //定义一个面板对象,所谓面板就是一种存放各种控件的容器罢了
pbutton.resize(500,100);
addButton(pbutton,bStart,"开始");
addButton(pbutton,bPause,"暂停");
addButton(pbutton,bContinue,"继续");
addButton(pbutton,bEnd,"结束");//在面板上加在以上按钮
addGrid(pbutton,cons,1,0,9,2);//addGrid函数在下面的代码中有定义
pProdC=new CProducerCanvas();
addGrid(pProdC,cons,1,2,1,2);
cConsC=new CConsumerCanvas();
addGrid(cConsC,cons,10,2,1,2);//创建对象并放到屏幕上
cons.anchor=GridBagConstraints.WEST;
trace1 = new CTrace1();
addGrid(trace1,cons,2,3,2,1);
cons.anchor=GridBagConstraints.EAST;
trace2 = new CTrace2();
addGrid(trace2,cons,8,3,2,1);
cons.anchor=GridBagConstraints.NORTH;
bBufC=new CBufferCanvas(k);
addGrid(bBufC,cons,2,3,7,1);
cons.anchor=GridBagConstraints.NORTH;
introduce=new CIntroCanvas();
addGrid(introduce,cons,1,8,9,1);
bBuf=new CBuffer(this,k);//以上代码实现了整个图形界面的布局,大家可以不必关心每一个函数的用法
}
public void addGrid(Component c,GridBagConstraints gc,int x,
int y,int dx,int dy) //在此定义addGrid 函数
{
gc.gridx=x;
gc.gridy=y;
gc.gridwidth=dx;
gc.gridheight=dy;
add(c,gc);//add是系统自带的函数,用于把控件放到指定的位子上
}
public void addButton(Container c,Button b,String s) {
b.setLabel(s);
c.add(b);
b.addActionListener(this);//监听事件的发生
}
public void actionPerformed(ActionEvent evt)//处理监听到的相应事件
{
Button b=(Button)evt.getSource();
if(b==bStart) {
startp();//如果是开始按钮被按下,则执行startp()函数,
}
else if(b==bEnd) {
pProd.stop();//结束按钮执行的代码
cCons.stop();
bBuf.stop();
pProd=null;
cCons=null;
}
else if(b==bPause) {
pProd.suspend();
cCons.suspend();//停止按钮执行的相应函数
}
else if(b==bContinue) {
pProd.resume();
cCons.resume();//继续按钮执行的相应函数
}
}
public void startp() {
pProd = new CProducer(this);//在此定义startp()函数
cCons = new CConsumer(this);
bBufC.reset();//reset()函数在相应的对象中有定义,大家可以查看一下相应类中的代码
bBuf.reset();
pProdC.reset();
cConsC.reset();
trace1.reset();
trace2.reset();
trace1.repaint();
trace2.repaint();
}
}
class CProducerCanvas extends Canvas//定义CProducerCanvas类,
{
private boolean prod; //prod:false-未生产,true-生产
public CProducerCanvas() {
prod = false; //此类的构造函数
resize(60,300);
}
public void reset()//在此定义Reset函数
{
prod=false;//首先置成未生产
repaint();//重新执行paint函数,//在下面五行中有Paint函数的定义
}
synchronized public void update(boolean p){
prod = p;
repaint();
}
public void paint(Graphics g) {
g.drawString("生产者",10,20);
if(prod)
{
g.setColor(Color.red);//对应左上角的小球,如果正在生产,则小球是红颜色的
g.fillOval(20,50,15,15);
prod = false;
}
}
}
class CConsumerCanvas extends Canvas
{
private boolean cons; //cons:false-消费过了,true-要消费
public CConsumerCanvas() {//构造函数
cons = false;
resize(60,300);
}
public void reset()//实现重置功能
{
cons=false;//消费过了
repaint();//重新执行下面的Paint()函数
}
synchronized public void update(boolean c){
cons = c;
repaint();
}
public void paint(Graphics g) {
g.drawString("消费者",10,20);
if(cons)
{
g.setColor(Color.green);
g.fillOval(20,50,15,15);//对应右上角小球,如果要消费,则是绿颜色的.
cons = false;//
}
}
}
class CBufferCanvas extends Canvas//缓冲区,即我们看到的中间那五个方格
{
private int k,num;
private boolean[] isFull;//定义一个布尔类型的数组,用于分别判断那五个缓冲区是否已经满了
private boolean CanPut,CanGet;//定义两个布尔型变量,分别用于判断缓冲区是否能够放或者取
public CBufferCanvas(int k){
resize(300,110);//构造函数
this.k=k;
isFull=new boolean[k];
for(int i=0;i<k;i++) isFull[i]=false;//分别置成空
num=-1;
CanPut=false;
CanGet=false;
}
public void reset() {
num=-1;
CanPut=false;
CanGet=false;
for(int i=0;i<k;i++) isFull[i]=false;
repaint();
}
public void canput()
{
CanPut=true;
repaint();
}
public void put()
{
num++;
isFull[num]=true;
repaint();
}
public void set_put()
{
CanPut=false;
repaint();
}
public void get()
{
isFull[num]=false;
num--;
CanGet=true;
repaint();
}
public void set_get()
{
CanGet=false;
repaint();
}
public void paint(Graphics g) {//真正要执行的部分
for(int n=0;n<k;n++) {
g.setColor(Color.black);
g.drawRect(40*n+50,60,40,35);//画矩形,Black为所用的颜色
if(isFull[n]) {
g.setColor(Color.green);
g.fillRect(40*n+51,61,39,34);//填充矩形,Green为所用的颜色
}
}
if (CanPut)
{
g.setColor(Color.black);
g.drawLine(50,60,40,50);
g.drawLine(50,95,40,105);
}
else if (CanGet)
{
g.setColor(Color.black);
g.drawLine(40*(k-1)+90,60,40*(k-1)+100,50);
g.drawLine(40*(k-1)+90,95,40*(k-1)+100,105);
}
}
}
class CBuffer extends Thread //是一个进程,本例中一共有三个.
{
private int k,num;
private boolean[] isFull;
private boolean CanPut,CanGet;
Producer_Consumer ps;//声明一个Producer_Consumer对象,
public CBuffer(Producer_Consumer ps,int k){ //是一个构造含数,注意其中的两小参数
this.k=k;//第一个K是上面定义的私有变量,第二个K是此构造函数的参数
isFull=new boolean[k];
for(int i=0;i<k;i++) isFull[i]=false;
num=-1;
CanPut=false;
CanGet=false;
this.ps=ps;
}
public void reset() {
num=-1;
CanPut=false;
CanGet=false;
for(int i=0;i<k;i++) isFull[i]=false;
}
public synchronized void put()
{
while (num+1==k){//如果缓冲区已满,则执行Set_put函数,
ps.bBufC.set_put();
try{
wait();//因为满了嘛,所以要等有空位子了
}
catch(InterruptedException e){}//Try,Catch是Java中的异常与捕获,这里大家可以不必了解
}
isFull[++num]=true;//如果没有满,则执行以下的代码
CanPut=true;
ps.bBufC.canput();
ps.trace1.go();
ps.bBufC.put();
notify();
try{
Thread.sleep(500);//500为时间量
}catch(InterruptedException e){}
ps.pProdC.reset();
ps.bBufC.set_put();
}
public synchronized void get()
{
while (num==-1)//如果缓冲区空了,则执行下面的语句
{
ps.bBufC.set_get();//不可取了
try{
wait();//要等待了,直到有东西可取
}
catch(InterruptedException e){}//在此期间,当系统出现中断时的处理
}
isFull[num--]=false;//如果不空,则执行以下语句
CanGet=true;
ps.bBufC.get();
ps.trace2.go();
notify();//?
try{
Thread.sleep(500);
}catch(InterruptedException e){}
ps.cConsC.reset();
ps.bBufC.set_get();
}
public void run(){
while (true)
{
try{
Thread.sleep((int)(Math.random()*5000));
}
catch (InterruptedException e){}
}
}
}
class CTrace1 extends Canvas
{
public int p,pend=23; //p:初始位置;endp:共多少次画面
public CTrace1(){
p=-1;
resize(100,50);
}
public void go(){
p=0;
while(p<pend) {
try { Thread.sleep(50); //估计是50毫秒,我们可以看到小球的轨迹
} catch(InterruptedException ex){}
repaint();
p++;
}
}
public void reset() {p=-1;}//置回初始位置
public void paint(Graphics g) {
if((p<(pend-1))&&(p>=0)) {
g.setColor(Color.red);
g.fillOval(p*2,10,12,12);//可以看到由于P*2,才使小球有了轨迹
}
}
}
class CTrace2 extends Canvas//与CTrace1原理是一样的
{
public int p,pend=23; //p:初始位置;endp:共多少次画面
public CTrace2(){
p=-1;
resize(100,50);
}
public void go(){
p=0;
while(p<pend) {
try { Thread.sleep(50);
} catch(InterruptedException ex){}
repaint();
p++;
}
}
public void reset() {p=-1;}
public void paint(Graphics g) {
if((p<(pend-1))&&(p>=0)) {
g.setColor(Color.green);
g.fillOval(p*2,10,12,12);
}
}
}
class CIntroCanvas extends Canvas {//是一块提示画布
private String s0,s1,s2,s3,s4,s5,s6,s7,s8;
public CIntroCanvas() {
resize(300,145);
s0="生产者-消费者问题例示:";
s1="生产者生产一个物品,放到BUFFER中;";
s2="消费者需要消费,也从BUFFER中取。";
s3="生产者生产一个物品后,其下方有红灯表示。";
s4="消费者要消费时,提出请求,其下方有绿灯表示。";
s5="当缓冲区控制台发现可以让生产者放置物品时,";
s6="对应着生产者的Buffer门打开。";
s7="当缓冲区控制台发现可以让消费者取物品时,";
s8="对应着消费者的Buffer门打开。";
}
public void paint(Graphics g) {
g.drawString(s0,0,10);//位置罢了
g.drawString(s1,10,25);
g.drawString(s2,10,40);
g.drawString(s3,10,55);
g.drawString(s4,10,70);
g.drawString(s5,10,85);
g.drawString(s6,10,100);
g.drawString(s7,10,115);
g.drawString(s8,10,130);
}
}
class CConsumer extends Thread //消费者的进程
{
Producer_Consumer pc;
public CConsumer(Producer_Consumer pc)//构造函数,注意其中的参数
{
this.pc=pc;
pc.cConsC.update(false);//消费过了,Update函数可以在Producer_Csonsumer类中查到
this.start(); //
}
public void run()
{
while (true)
{
pc.cConsC.update(true); //要消费
pc.bBuf.get();//从缓冲区中取东西了
try{
Thread.sleep((int)(Math.random()*Producer_Consumer.SPEED));
}catch(InterruptedException e){}//这里对应着加速消费速度按钮和减慢减慢消费速度按钮
}
}
}
class CProducer extends Thread//生产者的进程
{
Producer_Consumer pc;
public CProducer(Producer_Consumer pc)//构造函数
{
this.pc = pc;
pc.pProdC.update(false);
this.start();
}
public void run()
{
while(true)
{
pc.pProdC.update(true);//要生产了
pc.bBuf.put();//把生产的东西放到缓冲区中
try{
Thread.sleep((int)(Math.random()*Producer_Consumer.SPEED));
}catch(InterruptedException e){}//这里对应着加快生产速度按钮和减慢生产速度按钮
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -