阻塞队列以及生产者消费者模型

阻塞队列

阻塞队列,带有阻塞功能

1.当队列满的时候,继续入队列,就会出现阻塞,阻塞到其他线程能够从队列中取走元素为止

2.当队列空的时候,继续出队列,也会出现阻塞.阻塞到其他线程往队列中添加元素为止.基于阻塞队列,实现生产者消费者模型.

生产者消费者模型

生产者消费者模型优势

1.减少任务切换开销,减少锁竞争
2.解耦合

解耦合,就是"降低模块之间的耦合"

缺陷:效率会降低.

上述情况下,A是直接把请求发送给B的,A和B直接的耦合就比较明显

1.如果B挂了,就可能会对A造成很大影响,如果A挂了,也会对B造成很大影响

2.假设要再添加一个C,此时就需要对A的代码进行较大的改动.

此时,A和B就很好的解耦合了,现在,如果A或者B挂了,由于他们彼此之间不会直接交互,所以没有什么太大的影响.如果要新增一个服务器C,此时A服务器完全不需要任何修改,只让C也从队列中去取元素即可.

3.削峰填谷

服务器收到的来自于客户端/用户的请求,不是一成不变的,可能会因为一些突发事件,引起请求数目暴增.

一台服务器,同一时刻能处理的请求数量是有上限的,不同的服务器承担的上限是不一样的.

 机器的硬件资源有限(CPU, 内存,硬盘,网络带宽....) 服务器每次处理一个请求, 都需要消耗一定的硬件资源~~ 不同的服务器配置不同(提供的硬件资源就不同),处理的任务不同(每个请求消耗的资源也不同)

一个分布式系统中,就经常会出现,有的机器能承担的压力更大,有的则更小

正因为生产者消费者模型这么重要,虽然阻塞队列只是一个数据结构,但我们会把这个数据结构单独实现成一个服务器程序,并且使用单独的主机/主机集群来部署,此时,这个所谓的阻塞队列,就进化成了"消息队列".

Java标准库中也为我们提供了阻塞队列我们可以看到,当我们获取了hehe之后,想要再次获取,此时队列当中是没有数据的,此时就会进入阻塞等待.对于 BlockQueue来说,offer和poll不带有阻塞功能,put和take带有阻塞功能.

实现阻塞队列

上述代码只是一个普通的循环队列,接下来我们把它改造成一个阻塞队列.

1.解决线程安全问题我们直接给方法用synchronized来修饰.

2.内存可见性问题

我们这里既涉及到读操作,又涉及到写操作,极有可能一个线程在读,而另一个线程在修改.

3.阻塞等待

有两种情况,第一种是队列满了第二种情况就是队列为空此处的两个wait不会同时出现,要么是队满的时候wait,要么是队空的时候wait,毕竟一个队列不能即是空,又是满.

上述代码中,满足条件就进行wait,当wait被唤醒之后,条件就一定被打破了吗?

比如,当前我这边put操作因为队列满了,从而导致wait被阻塞了,过了一阵wait被唤醒了,唤醒的时候,此时的队列一定就不满了吗?万一出现了,唤醒之后队列还是满着的,此时就意味着接下来的代码继续执行,就可能把以前存入的元素给覆盖了.

wait一定只是notify唤醒吗?interrupt呢?

在当前的代码中,如果是interrupt唤醒了,此时直接引起异常,方法就结束了,不会继续执行,也就不会导致刚才所说的覆盖已有元素的问题.

如果是按照 try catch 的方式来写

一旦是interrupt唤醒,此时代码就会继续往下走,进入 catch,catch执行完毕时方法并不会结束,继续往下执行,也就触发了"覆盖元素"逻辑.

上述分析发现,这个代码只是侥幸写对了,稍微变换一下,就会出现问题,实际这么写的时候,很难注意到这个细节.

那么是否有办法,让这个代码万无一失呢?即使按照 try catch 的方式写,也没事呢?

很简单,等wait醒了之后再判断一次条件呗,如果条件还是队列满,继续wait.如果条件不满,就可以继续执行了Java官方文档告诉我们,使用wait的时候,建议搭配while进行条件判定.上述就是我们利用自己写的阻塞队列来实现的一个消费者生产者模型.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值