由存钱想到的”致富之路“——浅谈Java生产者消费者模型

由存钱想到的“致富之路”—— 关于数据统一

在网络支付和互联金融高度发达的今天,去银行Pos机或者柜台存钱似乎已经不那么多见了。约莫十年前,大街小巷是仍然可见到处的Pos机前来来往往的人流:神色凝重,表情严肃,着墨镜,戴帽子,手中紧握鼓鼓的包袱,似乎在拍港警片中抢银行的桥段。那时候的我也不例外。

然而,在许多次Pos机前杀青后我突然开始思索一个事情:如果有可能的话,我和我隔的小王同时在不同的Pos机上面操作同一张银行卡上面相同的500元钱,同时取出全部余额,如果我们的动作整齐划一,不分先后,完完全全同步的话,那么是不是我和小王都可以取到100元钱,然而银行卡余额剩下400元?

想着想着,我愈发觉得我的想法成熟。我和小王访问的是相同的500元钱相同的500元钱就意味着相同的数据相同的数据就意味着相同的访问权限和地位,也就是说,只要我能取出来,他就一定能取出来。

思已至此,我似乎探索出了新的致富之路。然而时至今日,当我在电脑前敲Java的时候,我想起了那些年的致富之路,我又觉得我行了。

Java内并发协作—— 线程的生产者消费者模型

提到并发协作,那就不得不提生产者和消费者的模型。事实上,生产者消费者的模型一般还要依存于库存的概念,也就是说,脱离了库存,似乎生产者和消费者就失去了很大一部分概念。

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而**通过阻塞队列来进行通讯,**所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

回想上文提到的致富之路银行卡内余额库存小王分别可以代表消费者生产者,同时对银行里同一数据进行访问
既然提到了库存的概念,我们就要创立一个类来实现库存的概念,模拟卡内余额

public class Store {
	   
	 public int curnum;//当前库存量  
	 
	 //构造方法,显示初始库存量
	 public Store(int curnum) {
		 this.curnum = curnum;
	 }
	 
	 //生产者生产,增加库存
	 public void produce(int produceNum) {
		 curnum = curnum + produceNum;
	 }
	 
	 //消费者消费,减少库存
	 public void reduce(int reduceNum) {
		 curnum = curnum - reduceNum;
	 }
	 
	 //显示当前库存
	 public void show() {
		 System.out.println(this.curnum);
	 }
}
生产者线程:
public class Producer extends Thread {
	Store store;
	int produceNum;
	public Producer(Store store, int produceNum) {
		this.store = store;
		this.produceNum = produceNum;
	}
	public void run() {
		store.produce(this.produceNum);
	}
}

消费者线程:
public class Reducer extends Thread {
	Store store;
	int reduceNum;
	public Reducer(Store store, int reduceNum) {
		this.store = store;
		this.reduceNum = reduceNum;
	}
	public void run() {
		store.reduce(this.reduceNum);
	}
}

下面创建一个银行卡对象进行取钱的测试。假设银行卡内一开始有500元钱。

public static void main (String args[]) {
		 Store myStore = new Store(500);
	 }

我取100元钱:

Reducer r1 = new Reducer(myStore,100);
		 r1.start();

小王再取100元钱:

Reducer r2 = new Reducer(myStore,100);
		 r2.start();

这个时候如果银行不是傻子的话卡里应该还剩下300元钱,但是按照我之前的逻辑似
乎也没有什么错误,那么我们来看看到底还剩下多少钱。

myStore.show();

在这里插入图片描述
结果如我所愿,还剩400。那么银行真的像我们说的一样是傻子吗,这一次决定多做些次操作,我带着我和小王,以及小王的同学,分别对同一余额进行操作:
银行卡初始余额500
我存入100
小王取出200;
8名同学每人取出10
那么按照正常思路应该最后余额为500+100-200-80=320,那实际输出结果是多少呢?
在这里插入图片描述

又一次被余额打脸了,而且这一次最后余额间歇的出现了330,350,360三个不同的值

如何做到数据统一—— 解决办法

由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。这种机制就是synchronized关键字。
synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线 程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法
优化后的代码如下:

 //生产者生产,增加库存
	 public  synchronized void produce(int produceNum) {
		 curnum = curnum + produceNum;
		 
	 }
//消费者消费,减少库存
	 public  synchronized void reduce(int reduceNum) {
		 curnum = curnum - reduceNum;
		 	 
	 }

输出结果:在这里插入图片描述
总结:在生产者-消费者模型中,最重要的也是最需要控制的地方就是保证同一个数据在同一时间只被同一线程访问,或做修改等操作,而在JAVA中,能够达到这样目的的代码方式不仅有synchronized关键字,欲知其他方法,请看下一篇博客。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值