分析线程经典案例生产者消费者

 /**
共享数据
*/
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;
notify();
} public synchronized void out()
{
if(!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + "==消费者==" + this.name);
flag = false;
notify();
}
} //定义线程任务(生产者线程)
class Producer implements Runnable
{
private Resource r; Producer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("商品");
}
}
}
//定义线程任务(消费者线程)
class Consumer implements Runnable
{
private 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 p=new Producer(r);
Consumer c=new Consumer(r);
//实例化线程,指定线程任务
Thread t0=new Thread(p);
Thread t1=new Thread(p);
Thread t2=new Thread(c);
Thread t3=new Thread(c);
//开启线程,执行线程任务中的run方法
t0.start();
t1.start();
t2.start();
t3.start();
}
}

运行结果:

结果分析:

那么怎么再判断flag呢?while

代码如下:

 class Resource
{
private String name;
private int count=1;
private boolean flag=false; public synchronized void set(String name) // 有两个线程t0 t1
{
while(flag)
try{this.wait();}catch(InterruptedException e){}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
flag = true;
notify();
} public synchronized void out() // 有两个线程t2 t3
{
while(!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + "==消费者==" + this.name);
flag = false;
notify();
}
}

结果出现死锁:

结果分析:

通过分析,那能不能每次唤醒只唤醒对方线程(如生产者线程只唤醒消费者线程,消费者线程只唤醒生产者线程),查看Object对象方法中没有,但是有一个notifyAll()方法,实在不行就把所有阻塞线程(相同同步锁的线程)都唤醒。

 class Resource
{
private String name;
private int count=1;
private boolean flag=false; public synchronized void set(String name) // 有两个线程t0 t1
{
while(flag)
try{this.wait();}catch(InterruptedException e){}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
flag = true;
notifyAll();
} public synchronized void out() // 有两个线程t2 t3
{
while(!flag)
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + "==消费者==" + this.name);
flag = false;
notifyAll();
}
}

结果:

这样就可以了。

总结:

if判断只能判断一次,如果执行等待方法,下次唤醒的线程获取执行权后(唤醒后的线程会从上次等待位置,向下执行)就不能再判断

while判断解决唤醒的线程获取执行权后无法判断

notify:只能唤醒任意一个线程,有可能会唤醒本方线程,while+notify会导致死锁

notifyAll:解决了死锁问题

Java学习之线程通信(多线程(synchronized))--生产者消费者的更多相关文章

  1. Java学习之线程通信(多线程(Lock))--生产者消费者

    SDK1.5版本以后对synchronized的升级,其思想是:将同步和锁封装成对象,其对象中包含操作锁的动作. 代码: //1.导入包 import java.util.concurrent.loc ...

  2. 【多线程】java多线程实现生产者消费者模式

    思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...

  3. Java并发包——线程通信

    Java并发包——线程通信 摘要:本文主要学习了Java并发包里有关线程通信的一些知识. 部分内容来自以下博客: https://www.cnblogs.com/skywang12345/p/3496 ...

  4. java多线程模拟生产者消费者问题,公司面试常常问的题。。。

    package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...

  5. Java多线程_生产者消费者模式2

    在我的上一条博客中,已经介绍到了多线程的经典案列——生产者消费者模式,但是在上篇中用的是传统的麻烦的非阻塞队列实现的.在这篇博客中我将介绍另一种方式就是:用阻塞队列完成生产者消费者模式,可以使用多种阻 ...

  6. java多线程解决生产者消费者问题

    import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...

  7. Java并发基础--线程通信

    java中实现线程通信的四种方式 1.synchronized同步 多个线程之间可以借助synchronized关键字来进行间接通信,本质上是通过共享对象进行通信.如下: public class S ...

  8. Android-Java多线程通讯(生产者 消费者)&10条线程对-等待唤醒/机制的管理

    上一篇博客 Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 是两条线程(Thread-0 / Thread-1) 在被CPU随机切换执行: 而今天这篇博客是,在上一篇博客A ...

  9. 【多线程】--生产者消费者模式--Lock版本

    在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...

随机推荐

  1. JavaScript高级程序设计(第3版) 第四章(变量、作用域和内存问题)

    4.1 基本类型和引用类型的值             1.基本类型的值是(简单的数据段),引用类型的值是(保存在内存中的对象). 基本类型的值在内存中占据固定大小的空间,因此被保存在栈中.(lifo ...

  2. jQuery基础--事件处理

    2. jQuery事件机制 JavaScript中已经学习过了事件,但是jQuery对JavaScript事件进行了封装,增加并扩展了事件处理机制.jQuery不仅提供了更加优雅的事件处理语法,而且极 ...

  3. java8新特性-简介

    一.主要内容 :其中最为核心的为lambda 表达式 与 Stream API lambda表达式 函数式接口 方法引用与构造器引用 Stream API 接口中的默认方法与静态方法 新时间日期API ...

  4. LeetCode #657. Robot Return to Origin 机器人能否返回原点

    https://leetcode-cn.com/problems/robot-return-to-origin/ 设置 flagUD 记录机器人相对于原点在纵向上的最终位置 flagRL 记录机器人相 ...

  5. 用Emacs编写mybatis

    用Emacs编写mybatis */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} ...

  6. Centos6.5 使用YUM安装MariaDB

    1,第一步 [xxxxxx]$ cd /etc/yum.repos.d [xxxxxx]$ vi MariaDB.repo # MariaDB 10.0 CentOS repository list ...

  7. Spark链接hive时 “HikariCP” 问题

    IDE本地调试和spark-shell调试报错: Caused by: org.datanucleus.exceptions.NucleusUserException: The connection ...

  8. jquery实现全选,反选,取消的操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. Asp.Netcore使用Filter来实现接口的全局异常拦截,以及前置拦截和后置拦截

    原文链接:https://blog.csdn.net/qq_38762313/article/details/85234594 全局异常拦截器:       解决写每个接口都需要去做容错而添加try{ ...

  10. 203-基于ARM和双TI DSP TMS320C6678的6UCPCI高清编解码处理平台

    基于ARM和双TI DSP TMS320C6678的6UCPCI高清编解码处理平台 1.产品简介 该板卡由我公司自主研发,以TI Cortex-A8.TI 双DSP TMS320C6678为设计核心, ...