关于生产消费模型的运用(教程)

简述一下生产/消费模型
无非就是两种情况
1.操作一个数据,到达设定的条件时,唤醒另外的线程,休眠自己。
2.休眠时,被另外的线程唤醒,继续进行操作。

关键方法:wait() notify()synchronized()
对于单对应生产/消费,可以直接使用wait、和notify,对于多对应生产/消费,只需要在下面添加一句while(设定的条件),具体可以查看JAVA帮助文档或者源码。而synhronized基本和他们配套,具体可看上一篇文章。

接下来,我们使用这种单对应的生产/消费模型来做一个简单的动画,让一个图形从界面由左向右移动,到中间时,变成另一种图形,图形到达边界时,又重新开始。
思路
1.需要一个主界面来显示我们的图形,以及启动线程。并且创建标志类的对象来以便使用。
2.设置一个标志类,用来作为线程里的判断,同时,也可以从中创建对象,以此方便synchronized的使用。
3.一个线程用来做圆球的运动,当圆球运动到中间,线程唤醒方块线程,休眠自己。
4.一个线程用来做方块运动,一开始设置休眠状态。当被圆球线程唤醒时,方块从中间运动到边界,线程唤醒圆球线程,休眠自己。

第一步,让我们先来创建好窗体,也是我们的主函数。我们需要显示界面,启动两个线程,创建好标志类的对象。这些功能可以写作一个方法window(),最后,在主函数调用这个window()方法即可。

Mod.java

public class Mod extends JFrame{
	
	public void window() {
		
		//窗体创建
		this.setTitle("生产消费模型");
		this.setSize(500,500);
		
		//居中
		this.setLocationRelativeTo(null);
		
		//退出程序
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//设置窗口的背景色
		Container co=this.getContentPane();
        co.setBackground(Color.white) ;       
		
		//可视化
		this.setVisible(true);
		
		//传递画布
		Graphics g = this.getGraphics();
		
		//标志数据
		Warehouse container = new Warehouse();
		
		//方块线程
		Consumption L = new Consumption(g,container);
		L.setName("方塊綫程");
		L.start();
		
		//圆球线程
		Production k = new Production(g,container);
		k.setName("球形綫程");
		k.start();
		
	}
	
	public static void main(String[] agrs) {
		
		Mod o = new Mod();
		o.window();
		
	}

}

第二步,标志类的创建。没有太多需要解释的,比较简单。

Warehouse.java

public class Warehouse {
	//help为方块线程中的判断标志,作用是一开始让其处于休眠状态
	//flag为圆形线程中的判断标志,作用于help类似
	int help=1,flag=1;
	
	//temp用储存x上一步的坐标,用来擦除图形运行的轨迹。
	int x=0,y=250,temp;

}

第三步,我们的圆球线程。这是要作为一个线程类,我们一定要先继承Thread。这里我们需要一个构造器,来传递主函数Mod当中,我们要用的画布g标志类Warehouse对象container

构造器的语句:
public Production(Graphics g, Warehouse container) {
this.g = g;
this.container = container;
}
线程的方法里,使用标志help判断进行画球、唤醒方块线程,同时也有改变另一个标志flag的操作。具体解释可以看注释里写的内容。

Production.java

public class Production extends Thread {
	Graphics g;
	Warehouse container;

	public Production(Graphics g, Warehouse container) {
		this.g = g;
		this.container = container;
	}

	public void run() {

		while (true) {
			synchronized (container) {
				
				// help为1的时候,小球向做运动
				if (container.help == 1) {

					g.setColor(Color.BLACK);
					g.fillOval(container.x,container.y, 30, 30);
					container.temp = container.x;
					try {
						sleep(5);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					container.x++;
					//擦除上一步轨迹
					g.setColor(Color.white);
					g.fillOval(container.temp, container.y, 30, 30);

				// 当小球运行到屏幕中央,改变flag值唤醒另一个程序,改变help值睡眠自己
				if (container.x == 250 || container.x >250) {

					if(container.flag == 1) {
						container.flag = 2;
						container.notify();
						container.help = 2;
						try {
							container.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

				}

			}

		}
			
		}
	}
}

最后一步,方块线程,和上一步基本是一样的。只是需要一开始就是休眠状态,所以标志类里flag一个作用,就在这里。

public class Consumption extends Thread {

	Graphics g;
	Warehouse container;

	public Consumption(Graphics g, Warehouse container) {

		this.container = container;
		this.g = g;

	}

	public void run() {
		
		while (true) {
			synchronized (container) {
				if(container.flag == 2) {

					g.setColor(Color.black);
					g.fillRect(container.x, container.y, 30, 30);
					container.temp = container.x;
					try {
						sleep(5);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					container.x++;
					//擦除上一步轨迹
					g.setColor(Color.white);
					g.fillRect(container.temp, container.y, 30, 30);

					// 当方块横坐标大于500时,更改help值唤醒另一个线程,更改flag值使自己睡眠
					if (container.x == 500 || container.x > 500) {
						if(container.help == 2) {
							container.help = 1;
							//让x坐标返回起点
							container.x = 0;
							container.notify();
							container.flag = 1;
							try {
								container.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						
					}
				
				// 当flag = 1时,保持睡眠不动
				if (container.flag == 1) {
					try {
						wait();
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}

					// 当flag不等于1时,方块向右移动
				}

			}
			
			}

		}
	}
}

整个程序如何运作,大致像下面这张图一样(不是标准的流程图),只是为了更清楚的展示一个过程。

在这里插入图片描述
以上,我个人看来,生产/消费模型并不一定要拘泥于存取的模式,他类似于线程之间的互相沟通。”我做事,你可以先不做,当我累了休息一下,就告诉你来做“。这种思路可以运用到很多使用线程的程序中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值