在上一节当中我们说道了,java多线程当中单个消费者对应单个生产者的关系。这个时候有几个点需要注意一下,第一个就是把if判断flag的语句改成while这样能够避免,比如如果我们这个时候用if的话判断完为真之后,线程就睡过去了,但是当下一次线程notify的时候,这个时候生产者还有消费者,也就是一个锁上面的线程拥有线程苏醒的机会是等同的。这个时候,如果生产者冻结之后,紧接着notify的话这个时候苏醒的还可能是生产者,这是我们不愿意看到的。那我们应该如何来处理呢,这个时候我们就应该把if改成while因为while是个循环,当下一次该线程苏醒的时候还应到回过头来判断,flag标记,这样就避免了生产者自我唤醒的这种情况。

但是现在问题变了,就是这个时候有多个生产者还有多个消费者,我们知道当只有一个生产者还有一个消费者的时候,至少会唤醒其中的一个,那么要是多个生产者还有多个消费者呢,我们可以这样想一下,比如说这个时候有两个生产者A和B,还有两个消费者C和D,此时A生产完了之后,这个时候A就开始唤醒了,假如A唤醒了C这个时候C开始生产消费产品,消费完了之后开始通知其他线程,这个时候假如被唤醒的是D线程,因为flag是假的证明已经没有东西可消费了,这个时候他又冻结。那么这个时候其他线程就都被冻结了,这个时候就形成了死锁现象,如果要避免死锁现象的话,java又为我们提供了一个方法,叫做notifyAll()方法,这个方法的作用在于能够把所有的线程都唤醒,这样就能保证消费者还有生产者至少可以唤醒双方的一个线程,保证程序的正常运行。这样做的一个缺点就是其中还有一个属于己方的线程被唤醒,这样就浪费了资源。于是在jdk更新的时候,就为我们提供了一个新的api能够显式的来操作锁还有唤醒冻结线程,这个线程不再核心lang包当中,这个api在java.util.concurrent.locks这个包当中为我们提供了两个接口,一是Lock接口还有一个是Condition接口。Lock接口扩展的方法有lock()方法还有一个unlock方法,这里需要注意的一点是,无论如何一定要释放锁,这个时候就用到了前面异常所讲到的finally语句,无论如何一定要执行。Lock当中还扩展了一个方法就是newCondition()这个方法,这个方法的作用是给一个锁定义多个消息传递的方式也就是给线程绑定多个监视器,比如说生产者只唤醒消费者的线程,而不唤醒生产者的线程,同理消费者也是如此。同时在Lock当中等待的方法不是wait()方法,唤醒的方法也不是notify()方法,这两个方法分别对应Lock当中的await()方法和signal()方法。

我们综合上面所讲来用代码体现下:

 import java.util.concurrent.locks.*;
class KaoYa
{ int num = ; Lock l = new ReentrantLock(); Condition c1 = l.newCondition();
Condition c2 = l.newCondition(); boolean flag; public void produce() throws InterruptedException
{
l.lock(); try{
while(true)
{
while(flag)
c1.await();
System.out.println(Thread.currentThread().getName()+"KaoYa...."+num);
flag = true;
c2.signal();
} //num++; }finally
{
l.unlock();
}
} public void consume() throws InterruptedException
{
l.lock(); try{
while(true)
{
while(!flag)
c2.await();
System.out.println(Thread.currentThread().getName()+"KaoYa------"+num);
num++;
flag = false;
c1.signal();
}
}finally
{ l.unlock(); }
} } class Product implements Runnable
{ KaoYa k;
Product(KaoYa k)
{ this.k = k; } public void run()
{
try{
k.produce();
}catch(InterruptedException e)
{ }
}
} class Consume implements Runnable
{ KaoYa k;
Consume(KaoYa k)
{ this.k = k; } public void run()
{ try{
k.consume();
}catch(InterruptedException e)
{ } } } class LockDemo
{ public static void main(String[] args) { KaoYa k = new KaoYa();
Product p = new Product(k);
Consume c = new Consume(k); Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c); t1.start();
t2.start();
t3.start();
t4.start(); } }

java学习之多生产者和多消费者的更多相关文章

  1. 2.5多线程(Java学习笔记)生产者消费者模式

    一.什么是生产者消费者模式 生产者生产数据存放在缓冲区,消费者从缓冲区拿出数据处理. 可能大家会问这样有何好处? 1.解耦 由于有了缓冲区,生产者和消费者之间不直接依赖,耦合度降低,便于程序拓展和维护 ...

  2. java学习多线程之生产者消费者

    在java多线程当中还有一种关系需要我们来重点掌握,那就是生产者和消费者的关系.那么什么是生产者,什么是消费者呢?我们可以举个例子来说,有张三.李四负责生产烤鸭,王五.马六负责吃烤鸭,那么前者生产完烤 ...

  3. Java多线程-并发协作(生产者消费者模型)

    对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一样,Hello World!都是最经典的例子. 实际上,准确说应该是“生产者-消费者-仓储”模型,离开了仓 ...

  4. Java实现PV操作 | 生产者与消费者

    导语 在学习操作系统的过程中,PV操作是很重要的一个环节.然而面对书本上枯燥的代码,每一个爱好技术的人总是想能亲自去实现.现在我要推出一个专题,专门讲述如何用Java实现PV操作,让操作系统背后的逻辑 ...

  5. 使用Java的BlockingQueue实现生产者-消费者

    http://tonl.iteye.com/blog/1936391 使用Java的BlockingQueue实现生产者-消费者 博客分类: Java JavaBlockingQueue阻塞队列  B ...

  6. java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

    java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样 ...

  7. Java并发编程(4)--生产者与消费者模式介绍

    一.前言 这种模式在生活是最常见的,那么它的场景是什么样的呢? 下面是我假象的,假设有一个仓库,仓库有一个生产者和一个消费者,消费者过来消费的时候会检测仓库中是否有库存,如果没有了则等待生产,如果有就 ...

  8. Java多线程设计模式(2)生产者与消费者模式

    1 Producer-Consumer Pattern Producer-Consumer Pattern主要就是在生产者与消费者之间建立一个“桥梁参与者”,用来解决生产者线程与消费者线程之间速度的不 ...

  9. java 线程并发(生产者、消费者模式)

    线程并发协作(生产者/消费者模式) 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”. Ø 什么是生产者? 生产者指的是负责生产数 ...

随机推荐

  1. JQ动画事件

    1.会飞的li html: <ul id="ulL"> <li>中国</li> <li>美国</li> <li&g ...

  2. iOS开发——基于corelocation位置定位——工具类

    (代码工具类已写好,空闲时间整理成文档,待更新……)

  3. c语言全局变量与局部变量(当变量重名时)的使用情况

    在c语言中,变量有全局变量和局部变量之分,这一点和很多高级语言类似,如c#,java等.不过与c#,java中的局部变量如在全局变量作用域内则不允许与全局变量名相同,而c语言是允许这样做的.这样的做法 ...

  4. 当传递具有已修改行的 DataRow 集合时,更新要求有效的 UpdateCommand问题解决

    1.目前看主要因为两种,第一种是select语句没有包含主键列,select *  就可以解决.或 select 主键列 这里的主键是指的primary key而不是unique key 2.最重要的 ...

  5. 设置contentType

    //定义编码 header( 'Content-Type:text/html;charset=utf-8 '); //Atom header('Content-type: application/at ...

  6. 04_XML_04_XMLDTD语法

    [DTD语法约束细节] * 元素定义 * 属性定义 * 实体定义 [1.元素定义] 在DTD文档中使用ELEMENT声明一个XML元素,语法格式如下所示: <!ELEMENT   元素名称  元 ...

  7. HDU 4294 A Famous Equation(DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4249 题目大意:给一个a+b=c的表达式,但是a.b.c中部分位的数字丢失,并用?代替,问有多少种方案 ...

  8. HDU 4089 Activation(概率DP)(转)

    11年北京现场赛的题目.概率DP. 公式化简起来比较困难....而且就算结果做出来了,没有考虑特殊情况照样会WA到死的.... 去参加区域赛一定要考虑到各种情况.   像概率dp,公式推出来就很容易写 ...

  9. windows server 2008镜像重启后密码变为默认密码的问题的解决方案

    1. cmd中执行regedit,打开注册表: 修改HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cloudbase Solusions\Cloudbase-Init ...

  10. bzoj2732: [HNOI2012]射箭 半平面交

    这题乍一看与半平面交并没有什么卵联系,然而每个靶子都可以转化为两个半平面. scanf("%lf%lf%lf",&x,&ymin,&ymax); 于是乎就有 ...