您的位置:首页 > 编程语言 > Java开发

java多线程交互 经典实例__生产者与消费者模型

2012-06-13 16:39 453 查看
由于在项目中的一些教训,最近回顾了一下多线程,写了下面这样一个简单的实例。

多线程的重点应当在于,线程的交互和锁,锁用来保护数据的原子性,线程的交互用于更灵活的线程通信。

测试线程的交互性,线程间交互实现以下细节:

* 生产者—消费—仓库 模型
* 测试线程的交互性
* 主要实现:
* 第一:生产者 生产的消费品 存放到仓库中,当仓库满时,生产者停止生产
* 第二:消费者 到仓库中 使用消费品,当仓库没有消费品时,停止消费
* 第三:生产者 在仓库满停止生产后 通知消费者去消费
* 第四:消费者 在仓库没有消费品时 通知生产者生产
* 第五:生产者 不可以消亡除非没有消费者进行再消费 消费者可以消亡

直接上代码了啊:







在上述实例中 我们使用了 连个对象的锁,即stb对象的锁 和 lock对象的锁,stb对象的锁 用来保护数据的完整性,lock对象的锁用于 生产者线程与消费者线程之间的服务,

在上述有两个地方需要注意:

   第一:为什么要将 生产者线程 设置为守护线程 也就是后台线程,如果不设置成这样,又会产生什么样的结果。

第二:在消费者的同步代码块中 为什么有一个else 如果去掉else ,将if中的i--也去掉 ,会有什么问题,有什么原因导致呢?(如果你自己写你考虑到了吗?考虑到是什么原因了吗?)

代码应该不算很绕,关键是线程之间交互的一些细节需要注意,下面我们来看看以上两个问题:

  第一个问题:

      众多消费者 在将仓库中的消费品用完时 通知生产者进行生产 ,也就是说 只要有消费者存在就有可能将仓库中的消费品消费完,所以生产者线程 需要一直存在,直到没有消费者存在时,才能消亡,

      所以生成者线程 完全可以看做为一个服务程序,后台线程的生命周期 到用户线程全部消亡时 才会被销毁。

     如果不将生产者作为一个后台线程,由于lock对象 一直在处于等待状态 ,所以全部的消费者消亡后 生产者还会存在,如果不设置生产者为后台线程,那么它会一直存在,占用着系统资源。当然 如果这个服务能确保永远的进行服务,可以不设置成后台线程。

第二个问题:

首先启动生产者,生产者处于等待被唤醒状态,然后启动一千个消费者线程,当这些线程进行消费时,必须首先获得stb对象的锁才能够进行消费,当第i-1个线程消费掉最后一个消费品时(即stb对象的curr=0时),

          第i个消费者线程获得了stb对象的锁后,判断没有消费品了,通知生产者,然后调用wait方法,线程调用wait方法时,会放弃当前对象的锁,放弃对象的锁意味着 其他等待该对象锁的线程 争先获得该锁,由于没有消费品,有一些消费者即使获得了锁

         也会因没有物品而通知消费者进入等待状态,即在生产者获得stb对象的锁之前,所有获stb对象锁的消费者线程,都会处于等待状态,比如说有200个线程,处于等待状态,然后生产者获得线程,进行生产了max_size(100)个消费品,然后

         notifyAll所有等待stb对象的线程,由于等待线程执行的位置为i--;处,所以如果去掉else这个地方,如果那200个消费线程获得了stb对象的锁,并且执行stb.custom()方法,没有再次调用stb.haveThings()进行判断,那么就会出现消费品为负数的

         的情况,即使调用了haveThings方法,如果没有消费品时,还会在重复stb.wait()方法,所以此处为else存在的原因,也就一句话,当所有的消费者线程 阻塞在了 消费方法之前时,当他们再次获得锁时,会造成数据破坏的可能。

知识关键点:

当调用对象的wait方法时,会放弃对象的锁!

线程调用对象的 wait() notify() notifyAll() 方法时,必须在对象的同步环境中,即线程必须获得该对象的锁
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: