问题描述

若干进程通过有限的共享缓冲区交换数据。其中,X个“生产者”进程不断写入数据,而Y个“消费者”进程不断读出数据;共享缓冲区共有N个;任何时刻只能有一个进程可对公用缓冲池进行操作。

问题分析

  我们已经知道,这样设计就可以保证先后顺序:对于某一个需要后进行的进程:wait(sth),wait(mutex),signal(mutex),先进行的进程:wait(mutex),signal(mutex),signal(sth)。而本问题也有先后的问题,对于消费者来讲,只有先有货物才可以消费。对于生产者来讲只有有空位才可以生产。所以需要三个信号量,两个(full和empty)用来决定先后顺序,一个是共享共用缓冲池的标志。

  对于生产者(Producer):wait(empty),wait(mutex),其他操作,signal(mutex),signal(full)。

  对于消费者(Consumer):wait(full),wait(mutex),其他操作,signal(mutex),signal(empty)。



利用记录型信号量解决

运行环境

Java SE 12

实现思路

使用Semaphore类

void acquire(int permits) :获取指定数目的资源,如果无可用资源将会一直阻塞等待。相当于wait()。

void release(int permits): 释放指定数目的资源。相当于signal()。

代码实现

final int N=5;//仓库容量
	private static Integer count = 0;//现有资源数目
	final Semaphore empty = new Semaphore(N);//表示空的数目
    final Semaphore full = new Semaphore(0);//表示满的数目
    final Semaphore mutex = new Semaphore(1);
	public static void main(String[] args) {
			TestG test=new TestG();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
	}
	class Producer implements Runnable{
		@Override
		public void run() {
		    for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);//睡眠
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    empty.acquire(1);//wait(empty)
                    mutex.acquire();//wait(mutex)
                    count++;
                    System.out.println(Thread.currentThread().getName()+ "生产者正在生产,目前总共有" + count);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();//signal(mutex)
                    full.release(1);//signal(full)
                }
            }
		}
	}
	class Consumer implements Runnable{
		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				try {
					Thread.sleep(3000);//睡眠
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					full.acquire(1);//wait(full)
					mutex.acquire();//wait(mutex)
					count--;
					System.out.println(Thread.currentThread().getName()+ "消费者正在消费,目前还剩" + count);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					mutex.release();//signal(mutex)
					empty.release(1);//signal(empty)
				}
			}
		}
	}

运行截图

过程中出现的问题和注意点

因为Semaphore三个信号量都被声明为了final所以一旦被声明不再会改变,所以如果通过构造函数传进来N是不行的,因为在这之前Semaphore已经被声明并且无法更改。


利用AND信号集解决

运行环境

Java SE 12

实现思路

将wait(empty)和wait(mutex)、signal (mutex )和signal (full)、wait (full) 和wait (mutex )、signal (mutex )和signal (empty)结合起来。其实结合起来之后,full和empty就可以用一个标志表示了,在这里我设置为count表示资源数。用synchronized给mutex加锁实现同步。

代码实现

private static  Integer count=0;//表示现有货物资源数目

    private static String mutex = "mutex";//标志资源区(仓库)是不是被占用
	public static void main(String[] args) {
		Test test=new Test();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();

	}
	class Producer implements Runnable{

		@Override
		public void run() {
		    for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (mutex) {//同步
                    while (count == 10) {//仓库满了
                        try {
                            mutex.wait();//释放mutex的锁
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    //生产
                    count++;
                    System.out.println(Thread.currentThread().getName() + "生产者正在生产,货物共有"+count);
                    mutex.notifyAll();
                }
            }
		}

	}
	class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mutex) {//同步
                    while (count == 0) {
                        try {
                            mutex.wait();//释放mutex
                        } catch (Exception e) {
                        }
                    }
                    count--;//消费
                    System.out.println(Thread.currentThread().getName() + "消费者正在消费,货物还剩"+count);
                    mutex.notifyAll();
                }
            }
        }
}

运行截图

生产者消费者问题中的同步机制JAVA设计和实现的更多相关文章

  1. Java中的闪光点:ThreadLocal是线程Thead的局部变量,可替代同步机制的设计,值得学习和研究

    线程局部变量ThreadLocal,是Java支持的一种线程安全机制,目的是解决多线程的并发问题. 具体来讲,就是多个线程访问该实例对象的变量时,该实例对象将其存储为键值对的形式,保证各个线程(键)分 ...

  2. 生产者消费者模式中条件判断是使用while而不是if

    永远在循环(loop)里调用 wait 和 notify,不是在 If 语句现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你 ...

  3. python JoinableQueue在生产者消费者项目中的简单应用

    class multiprocessing.JoinableQueue([maxsize]) JoinableQueue, a Queue subclass, is a queue which add ...

  4. Java笔记1 : 在生产者消费者模式中,线程通信与共享数据,死锁问题与解决办法

    本例定义了4个类,这里说一下,方便下面讲解.分别是Product(产品),Producer(生产者),Consumer(消费者), Test(测试类). 多线程之间通信与共享数据只要引用同一内存区域就 ...

  5. java 中的同步机制

    对于有些场景,需要a.b线程按照顺序去执行,因为b线程要依赖a线程对某共享资源或 状态处理后,对于这种情况可以使用 private CountDownLatch connectedSignal = n ...

  6. 对JavaScript中异步同步机制以及线程深入了解

    今天在网上看到各种对Js异步同步单线程多线程的讨论 经过前辈们的洗礼 加上鄙人小小的理解 就来纸上谈兵一下吧~ Js本身就是单线程的 至于为什么Js是单线程的 那就要追溯到Js的历史了 总而言之 由于 ...

  7. 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例

    wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视.本文对这些关键字的使用进行了描述. 在 Java 中可以用 wait ...

  8. Java 中 wait, notify 和 notifyAll的正确使用 – 以生产者消费者模型为例

    如何使用Wait 尽管关于wait和notify的概念很基础,它们也都是Object类的函数,但用它们来写代码却并不简单.如果你在面试中让应聘者来手写代码,用wait和notify解决生产者消费者问题 ...

  9. 【总结】Java线程同步机制深刻阐述

    原文:http://hxraid.iteye.com/blog/667437 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread ...

随机推荐

  1. Springboot:JSR303数据校验(五)

    @Validated //开启JSR303数据校验注解 校验规则如下: [一]空检查 @Null 验证对象是否为null @NotNull 验证对象是否不为null, 无法查检长度为0的字符串 @No ...

  2. mongodb connection refused because too many open connections: 819

    Env Debian 9 # 使用通用二进制方式安装 # mongod --version db version v3.4.21-2.19 git version: 2e0631f5e0d868dd5 ...

  3. JUC并发编程基石AQS之主流程源码解析

    前言 由于AQS的源码太过凝练,而且有很多分支比如取消排队.等待条件等,如果把所有的分支在一篇文章的写完可能会看懵,所以这篇文章主要是从正常流程先走一遍,重点不在取消排队等分支,之后会专门写一篇取消排 ...

  4. 编程语言千千万,为什么学习Python的占一半?

    如果让你从数百种的编程语言中选择一个入门语言?你会选择哪一个? 是应用率最高.长期霸占排行榜的常青藤 Java?是易于上手,难以精通的 C?还是在游戏和工具领域仍占主流地位的 C++?亦或是占据 Wi ...

  5. Hbase详细架构图解

    @ 目录 主要组件 数据模型 注意:Hbase是依赖zookeeper和hdfs的,需要启动zk和hdfs. 主要组件 Zookeeper: HBase 通过 Zookeeper 来做 Master ...

  6. /sbin/mount.vboxsf: mounting failed with the error: Protocol error

    公司换了新电脑,需要把之前的虚拟机的配置全部备份下来,在移动的过程中挂载共享文件夹时候出现了 /sbin/mount.vboxsf: mounting failed with the error: P ...

  7. java list随机截取(洗牌)

    public void solution(){ List<Integer> givenList = Arrays.asList(1, 2, 3,4,5,6); Collections.sh ...

  8. vue2.x学习笔记(三十二)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12684060.html. 深入响应式原理 vue最独特的特性之一,是其非侵入式(耦合度低)的响应式系统:数据模型仅 ...

  9. DM 源码阅读系列文章(六)relay log 的实现

    2019独角兽企业重金招聘Python工程师标准>>> 作者:张学程 本文为 DM 源码阅读系列文章的第六篇,在 上篇文章 中我们介绍了 binlog replication 处理单 ...

  10. AngularJS学习1-基础知识

    Angular并不是适合任何应用的开发,Angular考虑的是构建CRUD应用 但是目前好像也只是用到了angular的一些指令,数据绑定,mvc,http服务而已..... 以前传统的做法就是,通过 ...