class Meal{ private final int orderNum; Meal(int orderNum){ this.orderNum = orderNum; } public String toString(){ return "Meal " + orderNum; } } class WaitPerson implements Runnable{ private Restaurant restaurant; public WaitPerson(Restaurant r){ restaurant = r; } public void run(){ try { while (!Thread.interrupted()) { synchronized (this) { while (restaurant.meal == null) wait(); } System.out.println("Waitperson got " + restaurant.meal); synchronized (restaurant.chef) { restaurant.meal = null; restaurant.chef.notifyAll(); // ready for another } } } catch (Exception e) { System.out.println("WaitPerson interrupted"); } } } class Chef implements Runnable{ private Restaurant restaurant; private int count = 0; public Chef(Restaurant r){ restaurant = r; } public void run(){ try { while(!Thread.interrupted()){ synchronized(this){ while(restaurant.meal!=null) wait(); // for the meal to be taken; } if(++count == 10){ System.out.println("Out of fodd, clsosing"); restaurant.exec.shutdownNow(); } System.out.println("Order up! "); synchronized(restaurant.waitPerson){ restaurant.meal = new Meal(count); restaurant.waitPerson.notifyAll(); } TimeUnit.MILLISECONDS.sleep(100); } } catch (InterruptedException e) { System.out.println("Chef interrupted"); } } } public class Restaurant { Meal meal; ExecutorService exec = Executors.newCachedThreadPool(); WaitPerson waitPerson = new WaitPerson(this); Chef chef = new Chef(this); public Restaurant(){ exec.execute(chef); exec.execute(waitPerson); } public static void main(String[] args) { new Restaurant(); } }
Restaurant是WaitPerson和Chef的焦点, 他们都必须子回到在为哪个Restaurant工作,
因为他们必须和这家饭店的“餐窗”打交道, 以便放置或拿取restaurant.meal。 在run()
中, WiatPerson进入wait()模式, 停止其任务, 直到被Chef的notifyAll()唤醒。
由于这是一个非常简单的程序,因此我们直到只有一个任务将在WaitPerson的锁上
等待,即WaitPerson任务自身。 出于这个原因, 理论上可以调用notify()而不是
notifyAll()。 但是,在更复杂的情况下,可能会有多个任务在某个特定对象上
等待,因此就不知道哪个任务应该被唤醒,因此,调用notifyAll()更安全些,
这样可以唤醒等待这个锁的所有任务, 而每个任务都必须决定这个通知是否与
自己相关。
注意, wait()被包装在一个while()语句中, 这个语句在不断地测试正在等待的食物。
看上去有点怪-- 如果在等待一个订单,一旦被唤醒,这个订单就必须是可获得的,对嘛?
正如前面注意到的, 问题是在并发应用中, 某个洽谈的任务可能会在WaitPerson被唤醒,
会突然插足拿走订单,唯一安全的方式是使用下面这种wait()的惯用法
while(conditionIsNotMet)
wait();
对notifyAll()的调用必须首先捕获waitPerson上的锁, 而在WatiPerson.run()中
的对wati()的调用会自动地释放这个锁, 因此这是有可能实现的。 因为调用
notifyAll()必然拥有这个锁, 所以这保证两个试图在统一个对象上调用notifyAll()
的任务不会相互冲突。
通过把整个run()方法体放到一个try语句块中, 可使得这2个run()方法都被设计为
可以有序地关闭。 catch自居将紧挨着run()方法的结束括号之前结束,因此,如果这个任务
收到了InterruptedException异常, 它将在捕获异常之后立即结束。
注意, 在Chef中, 在调用shutdownNow()之后, 应该直接从run()中返回,并且通常这就是
你应该做的。 但是,以这种方式执行还有一些更有趣的东西。 shutdownNow()将向所有
由ExecutorService启动的任务发送interrupt(), 但是在Chef中,任务并没有获得该
interrupt()之后立即关闭, 因为当任务试图进入一个(可中断的)阻塞操作时,这个
中断只能抛出InterruptedException。 因此, 将看到首先显示了 "Order up!",然后
当Chef试图调用Slee()时, 抛出了InterruptedException. 如果移除对slee()的调用,
那么这个任务将回到run()循环的顶部,并由于Thread.interrupted()测试而退出,
同时并不抛出异常。
发表评论
-
仿真[汽车制造]
2012-02-13 01:26 684class Car{ private final i ... -
线程例子[Condition, SignlAll, await]
2012-02-09 22:05 1030package concurrency.waxomati ... -
泛型[创建类型实例]
2012-02-06 01:01 738public Class Erased<T> ... -
多路分发3
2012-02-05 23:16 826使用常量相关的方法 常量相关的方法允许我们为每个 ... -
多路分发2[使用enum分发]
2012-02-05 18:09 1902直接将RoShamBo1.java翻译为基于enum的版 ... -
多路分发
2012-02-05 02:06 1382多路分发 Number.plus(Number) ... -
使用Enum的自动贩卖机
2012-02-04 13:52 922public enum Input { NICKEL ... -
使用enum的责任链
2012-02-04 12:39 1178package enumerated; impor ... -
枚举类Enum,EnumSet,EnumMap
2012-02-04 02:00 1421EnumSet与HashSet相比,非常快。 p ... -
枚举类enum
2012-02-03 15:00 904一般来说,我们希望每个美剧实例能够返回对自身的描述, ... -
类的简化历[从内部类到匿名内部类]
2012-02-02 12:41 634Version1: public class DirL ... -
持有引用java.lang.ref 和 WeakHashMap
2012-02-02 01:27 981Thinking in java P554 持 ... -
Collections快速报错 fial-fast
2012-02-02 00:46 787{ public static void main( ... -
散列HashCode
2012-02-01 14:04 704散列的价值在于速度: 散列使得查询快速,由于瓶颈位于键 ... -
使用散列数据结构注意点
2012-02-01 01:32 590Goundhog自动继承基类Object,所以这里使用 ... -
Set注意点
2012-02-01 01:31 308如果我们尝试着将没有恰当支持不许的操作的类型用于需要这些 ... -
享元Map
2012-01-30 00:28 381这里之所以叫享元,注意static关键字。 定制了Entry ... -
深入容器Map
2012-01-19 15:12 398Map生成器 对Map的使用相同的方式,需要一 ... -
深入容器List
2012-01-19 14:40 342一种Generator解决方案: 所有Collect ... -
泛型数组
2012-01-19 00:57 637不能创建泛型数组,但能通过转型来赋予 public cl ...
相关推荐
创建一个简单的生产者消费者模型,可以使用以下伪代码: ```java class Producer implements Runnable { private final BlockingQueue<String> queue; public Producer(BlockingQueue<String> queue) { this....
### 利用管程与信号量解决生产者消费者问题 #### 概述 生产者-消费者问题是计算机科学中一个经典的问题,它用于演示进程间通信和同步的基本概念。该问题通常涉及一组生产者进程(负责生成数据)和一组消费者进程...
本示例中的“生产者-消费者”模型是一种经典的多线程问题,它模拟了实际生产环境中的资源分配与消耗过程。下面我们将详细探讨如何在Java中实现这个模型。 首先,我们要理解生产者-消费者模型的基本概念。在这个模型...
### 生产者消费者实验报告知识点总结 #### 实验目的与背景 本次实验旨在通过实践生产者消费者问题,深入了解操作系统中的进程通信与同步机制。实验选取了两种不同的操作系统平台——Linux和Windows,以此来对比和...
本示例通过简单的代码演示了如何使用 PV 操作解决生产者-消费者问题。尽管示例中的代码是基于 Java 编写的,但其核心思想和实现方式对于理解 C++ 中如何处理此类问题非常有用。通过使用适当的同步原语(如互斥锁和...
下面是一个简单的wait/notify实现生产者消费者模式的代码示例: ```java import java.util.LinkedList; import java.util.Queue; public class ProducerConsumer { private Queue<Integer> queue = new ...
在本文中,我们将通过一个简单的示例代码介绍Java实现简易生产者消费者模型的过程。 二、Java实现生产者消费者模型 在Java中,生产者消费者模型可以通过使用同步机制和wait/notify机制来实现。在下面的示例代码中...
"生产者消费者"问题是一个经典的多线程或进程同步问题,它用于演示和理解各种IPC机制。在这个场景中,生产者进程负责生成数据,而消费者进程则消费这些数据。下面我们将深入探讨Linux下的几种主要的IPC方法,以及...
以下是一个简单的示例,展示了如何在生产者消费者模型中应用这些概念: 1. 创建一个队列来存储数据。 2. 初始化一个信号量,例如:`Semaphore semaphore = new Semaphore(0, int.MaxValue);` 3. 生产者线程生成数据...
下面是一个简单的伪代码示例,展示了如何使用互斥锁和条件变量实现生产者消费者模式: ```python import threading buffer_size = 10 buffer = [None] * buffer_size count = 0 lock = threading.Lock() not_full ...
生产者消费者问题是多线程编程中的经典模型,用于展示如何有效地在并发环境下共享资源。这个问题源于现实世界的仓库模型,其中生产者负责生产商品,而消费者则负责消费这些商品。仓库作为一个缓冲区,存储有限的商品...
以下是一个简单的基于synchronized关键字和wait/notify机制的生产者消费者示例: ```java import java.util.LinkedList; public class ProducerConsumerExample { private final LinkedList<Object> buffer = new...
以下是一段简单的生产者消费者模式的代码示例: ```java import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumerExample { public static...
在计算机操作系统领域,生产者-消费者问题是经典的多线程同步问题,它展示了如何通过共享资源在并发环境中协调不同进程的行为。在这个问题中,"生产者"进程负责生成数据,而"消费者"进程则负责消费这些数据。为了...
- 以下是一个简单的使用`Channel`实现的生产者消费者模型的代码示例: ```csharp var channel = Channel.CreateBounded(10); // 创建一个容量为10的Channel Task.Run(async () => // 生产者线程 { for (int i...
下面是一个简单的生产者消费者模型实现: ```java import java.util.concurrent.ArrayBlockingQueue; public class ProducerConsumerExample { public static void main(String[] args) { ArrayBlockingQueue...
在"Kafka-java-demo"中,你将看到如何使用这些接口来实现一个简单的生产者和消费者示例。 【Kafka Producer】 Kafka生产者是负责将数据发布到Kafka主题的组件。在Java中,我们可以创建一个Producer实例,配置相关...
6. **示例代码**:一个简单的生产者消费者实现可能会包含两个线程,一个生产者线程负责将数据放入队列,一个消费者线程负责从队列中取出数据。每个线程都会在适当的时机调用`wait()`和`notify()`或`notifyAll()`来...
在Windows编程领域,生产者-消费者问题是多线程并发控制的经典案例。这个问题涉及到多个线程(生产者和消费者)共享一个有限的资源池,生产者生产数据,而消费者消费这些数据。PV操作,即信号量(Semaphore)的概念...