多生产者多消费者问题

以生产馒头 消费馒头为例。

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 (Exception e) {
// TODO: handle exception
}
}
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 (Exception e) {
// TODO: handle exception
}
}
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();
}
}
} public class Main
{
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);
t0.start();
t1.start();
t2.start();
t3.start();
}
}

上述代码easy出现一个问题,就是同一个馒头被多次消费。或者有的馒头没有被消费。单生者,单消费者不会出现这个问题

原因:notify 唤醒的线程是随意一个,比方t0 t1都是等待状态,t0活了之后,t1也可能被唤醒,所以就会产生多个馒头而没有被消费的情况,针对这个问题。flag的推断能够改为循环,这样却easy造成了死锁情况:t0 t1被wait了。t2正常消费一次,flag = false。唤醒了t0。由于循环t2 t3被wait了。t0运行一次,flag = true。如果唤醒t1。推断t0进行wait。while,t1也进入了等待,死锁状态

PS:冻结状态的线程被唤醒后本次就不參与推断,向下运行,所以简单来说,多个馒头没有被消费问题的产生,是由于冻结状态的线程不再继续參与推断造成的,而死锁是由于循环推断造成的

多生产多消费问题解决:

notify,改为notifyAll。当前本类线程中的一个正常运行后,唤醒全部线程,当前同类线程由于while,自然会继续等待,对方随意一个线程运行一次,对方剩余线程继续等待。这样就实现了生成相应消费

class Resource
{
private String name;
private int count = 1;
private boolean flag = false; public synchronized void set(String name)
{
while (flag)
{
try {
this.wait();
} catch (Exception e) {
// TODO: handle exception
}
}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"---生产者----"+this.name);
flag = true;
notifyAll();
}
public synchronized void out()
{
while (!flag) {
try {
this.wait();
} catch (Exception e) {
// TODO: handle exception
}
}
System.out.println(Thread.currentThread().getName()+"---------消费者--------"+this.name);
flag = false;
notifyAll();
}
}

总结:

if推断。仅仅会推断一次。easy造成不该唤醒的线程被唤醒了,出现故障

while推断,尽管攻克了线程获取执行权后。是否要执行

notify。仅仅能唤醒随意一个线程,可是唤醒本方线程,没有意义。且while+notify = 死锁

notifyAll,攻克了本方线程一定会唤醒对方线程

所以,多生产多消费问题 = while + notifyAll,可是也造成了效率低的问题(本方不该唤醒,也被唤醒了)

新特性(JDK1.5升级)

怎样不唤醒本方。仅仅唤醒对方呢

void Fu()//前期
{
synchronized (obj) //关于锁的操作是隐式的,仅仅有锁自己知道
{
code....
}
}
//后期升级,将锁这一事物封装成了对象 Lock L = new ReentrantLock();,将操作锁的隐式方式定义到了对象中
void Fu()
{
L.lock();//获取锁
code..
L.unlock();//释放锁
}

接口Lock

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现同意更灵活的结构。能够具有区别非常大的属性。能够支持多个相关的 Condition 对象。

ConditionObject 监视器方法(waitnotifynotifyAll)分解成截然不同的对象。以便通过将这些对象与随意
Lock 实现组合使用。为每一个对象提供多个等待 set(wait-set)。

当中,Lock 替代了
synchronized
方法和语句的使用。Condition 替代了 Object 监视器方法的使用。

Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}

Lock接口:替代了同步代码块或同步函数。将同步锁的隐式操作变成现实操作。更为灵活,能够一个锁加多个监视器

方法:

L.lock();//获取锁

L.unlock();//释放锁。一般与finally代码块连用

Condition接口:实现了Object中wait(),notify()。notifyAll()方法,将这些监视器方法进行了单独的封装,变成Condition监视器对象。能够随意锁进行组合

await()  相当于 wait

signal() 相当于 notify

signalAll(); 相当于 notifyAll

import java.util.concurrent.locks.*;

class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//创建一个锁
Lock L = new ReentrantLock();
//通过已有的锁,获取该锁监视器对象(Condition)
//Condition con = L.newCondition();
//通过已有的锁,获取两组监视器。一个监视生产者,一个监视消费者
Condition pro_con = L.newCondition();
Condition consu_con = L.newCondition(); public void set(String name)
{
L.lock();
try {
while (flag)
{
try {
pro_con.await();//线程冻结
}catch (Exception e) {
// TODO: handle exception
}
}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"---生产者5.0----"+this.name);
flag = true;
//con.signalAll();//唤醒全部线程
consu_con.signal();//唤醒消费者线程,不用All
} catch (Exception e) {
// TODO: handle exception
}
finally
{
L.unlock();//释放锁
} }
public void out()
{
L.lock();
try {
while (!flag) {
try {
consu_con.await();
} catch (Exception e) {
// TODO: handle exception
}
}
System.out.println(Thread.currentThread().getName()+"---------消费者5.0--------"+this.name);
flag = false;
//con.signalAll();
pro_con.signal();
} catch (Exception e) {
// TODO: handle exception
}
finally
{
L.unlock();
} }
} 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();
}
}
} public class Main
{
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);
t0.start();
t1.start();
t2.start();
t3.start();
}
}

实际开发是这种代码

class BoundedBuffer {//缓冲区
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];//创建一个大的容器
int putptr, takeptr, count; public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
} public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}

JAVA学习第二十七课(多线程(六))- 多生产者多消费者问题(JDK1.5新特性)的更多相关文章

  1. JAVA学习第二十一课(多线程(一)) - (初步了解)

    放假在家,歇了好几天了,也没学习,今天学习一下多线程.找找感觉.后天就要回学校了.sad... PS:包 没有什么技术含量,会用就可以,日后开发就必需要会用啦,所以打算先放一放,先来多线程 一.多线程 ...

  2. Python学习第二十七课——写一个和Django框架的自己的框架

    MyWeb框架: from wsgiref.simple_server import make_server def application(environ, start_response): pri ...

  3. 风炫安全WEB安全学习第二十七节课 XSS的防御措施

    风炫安全WEB安全学习第二十七节课 XSS的防御措施 XSS防御措施 总的原则 控制好输入/输出 过滤:根据业务需求进行过滤,对email,手机号码这样的输入框进行验证. 转义:所有输出到前端的数据都 ...

  4. NeHe OpenGL教程 第二十七课:影子

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  5. 风炫安全WEB安全学习第二十二节课 DOM型XSS讲解

    风炫安全WEB安全学习第二十二节课 DOM型XSS讲解 Dom型XSS演示 通过Javascript,可以重构整个HTML文档,你可以添加.移除.改变或重排页面上的项目 要改变页面的某个东西,Java ...

  6. 【MQ】java 从零开始实现消息队列 mq-02-如何实现生产者调用消费者?

    前景回顾 上一节我们学习了如何实现基于 netty 客服端和服务端的启动. [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]java 从零开始实现消息队列 mq-02-如何实现生产者调用 ...

  7. 201671010140. 2016-2017-2 《Java程序设计》java学习第二周

                                 学习第二周(Java基本程序设计结构)      这一周,着重学习了Java的简单程序设计实现及运行,通过自己操作,发现Java的程序语法大面 ...

  8. 2017年1月1日 java学习第二天复习

    今天是新年的第一天,以前学习没有总结习惯,学习效率和成果都很不好.  学习的过程就是反复的复习和不断学习的过程,开始今天的学习总结   学习java的第二天. 今天学习了java最基础的一些内容,照着 ...

  9. Java学习第二周学习笔记

    20145307<Java程序设计>第二周学习总结 教材学习内容总结 Java语言中的很多基本语法都和C语言类似,以下Java中的基本语法 标识符 标识符是程序中自定义的一些名称. 由26 ...

随机推荐

  1. Vue经典开源项目

    Vue常用的开源项目和插件库 UI组件 element ★34,784 - 饿了么出品的基于Vue2的web UI工具套件storybook ★33,503 - 响应式UI 开发及测试环境Vux ★1 ...

  2. redis基本数据类型和对应的底层数据结构

    Redis的数据类型包含string,list,hash,set,sorted set. Redis中定义了一个对象的结构体: /* * Redis 对象 */ typedef struct redi ...

  3. JSON数据的生成与解析

    JSON数据的生成与解析.首先先到网上下载一个json jar包,我用的是org.json 演示样例代码: package json; import org.json.JSONArray; impor ...

  4. leetCode 72.Edit Distance (编辑距离) 解题思路和方法

    Edit Distance Given two words word1 and word2, find the minimum number of steps required to convert  ...

  5. 弹性ScrollView,和下啦刷新的效果相似 实现下拉弹回和上拉弹回

    今天做了一个弹性ScrollView,和下啦刷新的效果类似,我想这个非常多需求都用的这样的效果 事实上这是一个自己定义的scrollView,上代码.这是我写在一个公共的组件包里的 package c ...

  6. 【Linux驱动】TQ2440 DM9000E网卡驱动移植(Linux-2.6.30.4)

    花了一天的时间研究了一下Linux-2.6.30.4版本号内核下关于TQ2440 DM9000E的网卡驱动移植.总结一下自己的收获. 事实上.在Linux-2.6.30.4版本号内核下有关于网卡驱动, ...

  7. Codeforces 701E Connecting Universities 贪心

    链接 Codeforces 701E Connecting Universities 题意 n个点的树,给你2*K个点,分成K对,使得两两之间的距离和最大 思路 贪心,思路挺巧妙的.首先dfs一遍记录 ...

  8. Kettle学习系列之Kettle的起源

    不多说,直接上干货! Kettle起源于十年以前,本世纪初.当时啊,ETL工具千姿百态,比较流行的工具有50个左右,ETL框架数量比工具还要多些. 根据这些工具的各自起源和功能可以分为以下4种类型,如 ...

  9. PowerDesigner 16.5 安装及破解步骤

     安装: 1.双击运行PowerDesigner16.5_Evaluation.exe,进入安装界面,点击(Next)下一步按钮: 2.下拉菜单选择HongKong,选中 I agree to the ...

  10. 来,我们来聊聊怎么学好3dMax三维建模这款软件

    效果图公司近年来的发展体现了流行3D技术,而3D技术的应用也越来越广泛,3D为电脑效果图制作的主力.室内效果是设计师进行设计后所达到的效果,除了通常采用的方法外,还应该积极地找寻一种适合的教学方法,培 ...