生产与消费模型

        实际生活中,需要操作共享的某个资源(水池),但是对这个共享资源操作方式不同(部分是注水【生产】、部分是抽水【消费】)。把这种现象我们可以称为生产和消费模型。

        生产:它可以采用部分线程进行模拟。多个线程同时给水池中注水。

        消费:它可以采用部分线程进行模拟。多个线程同时从水池中抽水。

        对资源的不同的操作方式,每种方式都可以让部分线程去负责。多个不同的线程,他们对相同的资源(超市、水池等)操作方式不一致。

        这个时候我们不能使用一个run方法对线程的任务进行封装。所以这里就需要定义不同的线程人物类,描述不同的线程任务。

        通过不同的线程操作,来控制同一个资源,这种现象就属于生产消费模型

简单是实现生产消费模型

        创建公共资源类

package com.test1;
/**
 * 被多个线程操作的共享数据的共享资源类
 * @author zxc
 *
 */
public class Resource {

	//注水的方法
	public void add(){

	}	
	//抽水的方法
	public void delete(){
	
	}
}

生产共享资源的目标类

package com.test1;
/**
 * 生产任务类
 * @author zxc
 *
 */
public class ShengChan implements Runnable{
	//定义共享资源对象
	private Resource resource;
	//通过构造方法传入共享资源对象
	public ShengChan(Resource resource){
		this.resource=resource;
	}
	@Override
	public void run() {

		//访问共享资源的生产方法
		 resource.add();
		
	}
}

消费资源共享的目标类

package com.test1;
/**
 * 消费共享资源的目标类
 * @author zxc
 *
 */
public class XiaoFei implements Runnable{
	//定义共享资源对象
	private Resource resource;
	//通过构造方法传入共享资源对象
	public XiaoFei(Resource resource){
		this.resource=resource;
	}
	@Override
	public void run() {

			//访问共享资源的消费方法
		resource.delete();
	
	}
}

测试主类

package com.test1;

public class TestMain {

	public static void main(String[] args) {
		//创建共享资源类对象
		Resource resource=new Resource();
		//创建生产共享资源的目标类对象
		ShengChan sc=new ShengChan(resource);
		//创建消费共享资源的目标对象
		XiaoFei xf=new XiaoFei(resource);
		//创建生产者线程对象
		Thread scthread=new Thread(sc);
		//创建消费者线程对象
		Thread xfthread=new Thread(xf);
		//启动生产和消费线程
		scthread.start();
		xfthread.start();

	}

}

修改Resource为add()/delete()添加具体实现动作

package com.test1;
/**
 * 被多个线程操作的共享数据的共享资源类
 * @author zxc
 *
 */
public class Resource {
	//保存共享资源的数据[水池]
	private Object objs[]=new Object[1];
	//记录生产和消费的次数
	private int num=1;
	//注水的方法
	public void add(){
		objs[0]="水"+num;
		System.out.println(Thread.currentThread().getName()+"正要注入的水是:"+objs[0]);
		num++;
	}	
	//抽水的方法
	public void delete(){
		System.out.println(Thread.currentThread().getName()+"抽出的水是:"+objs[0]);
		objs[0]=null;
	}
}

修改生产者的目标类为注水方法添加循环,以达到持续追谁的目标

package com.test1;
/**
 * 生产任务类
 * @author zxc
 *
 */
public class ShengChan implements Runnable{
	//定义共享资源对象
	private Resource resource;
	//通过构造方法传入共享资源对象
	public ShengChan(Resource resource){
		this.resource=resource;
	}
	@Override
	public void run() {
		//持续注水
		for(int i=1;i<=50;i++){
		//访问共享资源的生产方法
		 resource.add();
		}
	}
}

修改消费者的目标类为抽水方法添加循环,以达到持续抽水的目标

package com.test1;
/**
 * 消费共享资源的目标类
 * @author zxc
 *
 */
public class XiaoFei implements Runnable{
	//定义共享资源对象
	private Resource resource;
	//通过构造方法传入共享资源对象
	public XiaoFei(Resource resource){
		this.resource=resource;
	}
	@Override
	public void run() {
		//持续抽水
		for(int i=1;i<=50;i++){
			//访问共享资源的消费方法
		resource.delete();
		}
	}
}

 有时会消费者抽水为null的情况:

        有两个线程分别是生产者负责注水的线程和消费者负责抽水的线程。

        假设cpu在消费者线程上,那么消费者打印完抽水"水1"的情况下,还没有将数组空间赋值为null之前,cpu切换到生产者,生产者将水注到数组空间中之后,打印出正要注进入的水是:水2,cpu有切回到消费者线程上,消费者线程就会将数组空间立刻赋值为null。cpu如果再切回到生产者线程上,执行了注水次数加1之后。cpu如果在切回到消费者线程上,这时消费者线程就会输出抽水为null的情况

有时会出现生产者注水为null的情况:

        有两个线程分别是生产者负责注水的线程和消费者负责抽水的线程。

        假设cpu在消费者线程上,那么消费者正要打印了抽水为null的情况下,还没有将数组空间赋值为null之前,cpu切换到生产者,生产者将水注到数组空间中之后,还没有打印,cpu又切回到消费者线程上,消费者线程就会将数组空间卢克赋值为null。cpu如果再切回到生产者线程上,打印出来的注水就是null。

        上面这两个问题就是因为当前线程正在访问共享资源的时候,其他线程也可以访问共享资源所产生的。所以线程操作共享数据时,需要进行线程同步。

线程同步能够保证注水的时候不能抽水,或者抽水的时候不能给当前这个空间注水。

修改Resource为注水和抽水方法添加同步代码块保证注水的时候不能抽水,或者抽水的时候不能给当前这个空间注水


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值