在上一节当中我们说道了,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. javaweb入门20160305---xml的解析入门

    一个XML文件除了我们人去读写以外,我们希望可以通过程序去读写,利用程序去增删改查XML的过程就是XML编程 CRUD:Create.Read.Update.Delete   XML的两种解析方式 d ...

  2. 封装一个ISortable接口

    using System;/// <summary>/// 排序规范/// </summary>/// <typeparam name="T"> ...

  3. CDN调度器HAProxy、Nginx、Varnish

    http://www.ttlsa.com/web/the-cdn-scheduler-nginx-haproxy-varnish/ CDN功能如下:1.将全网IP分为若干个IP段组,分组的依据通常是运 ...

  4. iOS开发——音频篇——音乐的播放

    一.简单说明 音乐播放用到一个叫做AVAudioPlayer的类,这个类可以用于播放手机本地的音乐文件. 注意: (1)该类(AVAudioPlayer)只能用于播放本地音频. (2)时间比较短的(称 ...

  5. javaScript笔记1

    一.通过 id 访问HTML元素,可以使用 document.getElementById(id) 方法. 例子: <body> <button id="mybtn&quo ...

  6. 使windows server 2003 开机不显示登录页面

    1.运行“regedit”,以打开“注册表管理器”:运行注册表编辑器,依次展开[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersi ...

  7. 10.08_逛逛OSC

    (1)每天逛逛OSC是我的习惯了. JNative.JACOB.Shrinkwrap  API? .Lua.WSO2 Identity Server .JBoss Forge.Bugzilla.Cou ...

  8. Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作

    Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作 1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(Studen ...

  9. .net生成随机验证码图片

    /// <summary> /// 自定义图片验证码函数 /// 该函数将生成一个图片验证码,并将生成的code存放于Session["VerifyCode"]变量内. ...

  10. HTML 表格的书写方式:

    首先要进行reset  table{border-collapse:collapse;border-spacing:0;}th{text-align:inherit;} 1. caption标签对整个 ...