// 以生产和消费烤鸭为例
class Resource
{
private String name;
private int count = 1; // 记录烤鸭的编号
private boolean flag = false; public synchronized void set(String name)
{
if(flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
this.notify();
} public synchronized void out()
{
if(!flag)
try{this.wait();}catch(InterruptedException e){}
Sytem.out.println(Thread.currentThread().getName()+ "...消费者.."+ this.name);
flag = false;
this.notify();
}
} class Producer implements Runnable
{
Resource r;
Producer(Resource r)
{
this.r = r;
} public void run()
{
while(true)
{
r.set("烤鸭");
}
}
} class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ProducerConsumerDemo
{
public static void main(String[] args)
{
// 创建资源
Resource r = new Resource(); // 创建任务
Producer pro = new Producer(r);
Consumer con = new Consumer(r); // 多生产者
Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro); // 多消费者
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
Thread t5 = new Thread(con); // 开启线程
t0.start();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}

出现错误的两种情况:

  1. 线程安全问题(虚假唤醒): 线程1 生产的烤鸭被线程3 和线程5 两个线程同时消费

    • if 只能判断标记一次, 会导致不该运行的线程运行了, 出现数据错误的情况
    • while 可以多次判断标记, 解决了线程获取执行权后, 是否要运行的问题!

  1. 死锁

    • notify() 一次只能唤醒一个线程, 如果本方唤醒类本方, 没有意义. 而且 while 判断标记多次,

      会导致死锁.
    • notifyAll() 解决了本方线程一定会唤醒对方线程的问题.
// 升级版代码
class Resource
{
private String name;
private int count = 1; // 记录烤鸭的编号
private boolean flag = false; public synchronized void set(String name)
{
// 将 if 换为 while, 线程从冻结状态被唤醒后,需要判断 flag 标记之后, 确定是否继续生产"烤鸭"
while(flag)
try{this.wait();}catch(InterruptedException e){}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
this.notifyAll(); // 肯定会唤醒对方的线程, 解决了死锁问题
} public synchronized void out()
{
while(!flag)
try{this.wait();}catch(InterruptedException e){}
Sytem.out.println(Thread.currentThread().getName()+ "...消费者.."+ this.name);
flag = false;
this.notifyAll();
}
} class Producer implements Runnable
{
Resource r;
Producer(Resource r)
{
this.r = r;
} public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}

- [JavaSE 基础视频(毕向东)](https://www.bilibili.com/video/av3106510/#page=4)

Java 多线程通信之多生产者/多消费者的更多相关文章

  1. java 多线程并发系列之 生产者消费者模式的两种实现

    在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据 ...

  2. JAVA多线程通信

    JAVA多线程通信 package com.frank.thread; /** * author:pengyan * date:Jun 16, 2011 * file:ProducerAndCusto ...

  3. java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

     *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时 ...

  4. Java 多线程学习笔记:生产者消费者问题

    前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后 ...

  5. windows多线程(十) 生产者与消费者问题

    一.概述 生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池 ...

  6. java多线程系列15 设计模式 生产者 - 消费者模式

    生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...

  7. Java多线程之并发协作生产者消费者设计模式

    两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...

  8. Java多线程—阻塞队列和生产者-消费者模式

    阻塞队列支持生产者-消费者这种设计模式.该模式将“找出需要完成的工作”与“执行工作”这两个过程分离开来,并把工作项放入一个“待完成“列表中以便在随后处理,而不是找出后立即处理.生产者-消费者模式能简化 ...

  9. 线程间的通信_多生产者多消费者问题_JDK1.5新特性_Lock

    对于同步代码块,对于锁的操作是隐式的但是在JDK1.5之前的这种方法效率有点低,判断会很多,后面升级之后有新的解决方案 jdk1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将 ...

随机推荐

  1. [k8s]k8s-web-terminal配置使用 & etcdui etcd browser配置 & etcdkeeper3配置

    安装kube-dns后,我想看看他是怎么个配置,于是我就找到了这个 参考: https://github.com/beyondblog/k8s-web-terminal cat >> /e ...

  2. ecmall程序结构图与数据库表分析

    以下是ecmall的程序结构图,看了这张图,我们可以清楚的知道ecmall的程序结构. ECMALL数据库主要表如下所示: ecm_acategory:存放的是商城的文章分类.ecm_address: ...

  3. 利用jquery的contains实现搜索功能

    / jquery实现的搜索功能 $('#search_btn').on('click',function(){ var txt=$('#inputValue').val(); var value=$( ...

  4. 跟着百度学PHP[14]-PDO之Mysql的事务处理1

    事务处理:在实际案例当中干一件事的mysql语句(好比转账,小一同学转账100,小二同学收账,在mysql当中小一就要减去转账的钱,小二就要增加100快)倘若该语句执行过程中有任何一条的sql语句出错 ...

  5. Unity5.1 新的网络引擎UNET(四) UNET Remote Actions

    孙广东   2015.7.12 网络系统 具有网络中执行操作actions 的方法.这些类型的actions 有时是调用远程过程调用(Remote Procedure Calls). 在网络系统中有两 ...

  6. 碉堡完整的高性能PHP应用服务器appserver

    完全企业级的开发模式,是一个多线程的 PHP 应用服务器,实现真正多线程的 PHP 编程,高效安全而且快速,以Magento 为例比基于 Nginx的标准安装要快 50%.概念上非常像 Java 的 ...

  7. Prerender Application Level Middleware - ASP.NET Core Middleware

    In the previous post Use Prerender to improve AngularJS SEO, I have explained different solutions at ...

  8. 【Python】分享使用的插件文件链接(实时更新)

    链接:https://pan.baidu.com/s/1o7AgHtw Python工具实时更新.

  9. Service Mesh服务网格新生代--Istio(转)

    万字解读:Service Mesh服务网格新生代--Istio  官网地址:https://preliminary.istio.io/zh/docs/concepts/security/ Servic ...

  10. 用TortoiseSVN忽略文件或文件夹(ignore)(网络摘抄记录)

    Android项目需要协同一起开发时,就需要保证项目同步完整性.SVN忽略文件列表:.gradle .idea build local.properties *.iml app/*.iml app/b ...