Multi-Programming-9 非线程安全类实现生产者和消费者
来源:互联网 发布:gas mask mac 下载 编辑:程序博客网 时间:2024/06/05 03:59
1.生产者消费者问题
如果想看该问题详细描述,点击这里(不过是英文版本的)。
In computing, the producer–consumer problem[1][2] (also known as the bounded-buffer problem) is a classic example of a multi-process synchronization problem. The problem describes two processes, the producer and the consumer, who share a common, fixed-size buffer used as a queue. The producer’s job is to generate data, put it into the buffer, and start again. At the same time, the consumer is consuming the data (i.e., removing it from the buffer), one piece at a time. The problem is to make sure that the producer won’t try to add data into the buffer if it’s full and that the consumer won’t try to remove data from an empty buffer.
The solution for the producer is to either go to sleep or discard data if the buffer is full. The next time the consumer removes an item from the buffer, it notifies the producer, who starts to fill the buffer again. In the same way, the consumer can go to sleep if it finds the buffer to be empty. The next time the producer puts data into the buffer, it wakes up the sleeping consumer. The solution can be reached by means of inter-process communication, typically using semaphores. An inadequate solution could result in a deadlock where both processes are waiting to be awakened. The problem can also be generalized to have multiple producers and consumers.
生产者和消费者问题(也被叫做“有界缓冲区问题”)是一个经典的多线程同步问题的例子。生产者和消费者线程,共享一个共同的、固定大小的缓冲区,用作缓冲队列。
生产者的任务是产生数据,放入缓冲区,然后周而复始。同时,消费者消费数据(也就是从缓冲区移除一单位数据),每次消费一个单位。
问题在于:如何确保生产者不会再缓冲区满的时候添加数据;消费者不在缓冲区空的时候移除数据。
如何解决?
生产者:在缓冲区满的时候,要么休息,要么丢弃数据;当有消费者从缓冲区消费数据的时候,再唤醒生产者。
消费者:在缓冲区空的时候,休息;当生产者往缓冲区放数据的时候,唤醒消费者。
具体的解决方案:通过线程间通信解决,一般使用的是信号量机制(这里的术语均对应于操作系统,和Java中国年的Semaphore等有差异)。
- 可能导致死锁的代码
int itemCount = 0;procedure producer() { while (true) { item = produceItem(); if (itemCount == BUFFER_SIZE) { sleep(); } putItemIntoBuffer(item); itemCount = itemCount + 1; if (itemCount == 1) { wakeup(consumer); } }}procedure consumer() { while (true) { if (itemCount == 0) { sleep(); } item = removeItemFromBuffer(); itemCount = itemCount - 1; if (itemCount == BUFFER_SIZE - 1) { wakeup(producer); } consumeItem(item); }}
这里为何会死锁?
考虑:如消费者准备取数据的时候,itemCount为0,然后刚准备sleep(),结果被生产者中断,生产者生产了一个单位数据后,wakeup()消费者,然而此时消费者并没有sleep(),所以wakeup信号丢失(未起作用),之后消费者一直不回被唤醒(因为唤醒条件是itemCount==1),直至缓冲区满,生产者也去sleep(),结果生产者和消费者永远陷入sleep()状态,陷入死锁。
- Semaphore代码
mutex buffer_mutex; // similar to "semaphore buffer_mutex = 1", but different (see notes below)semaphore fillCount = 0;semaphore emptyCount = BUFFER_SIZE;procedure producer() { while (true) { item = produceItem(); down(emptyCount); down(buffer_mutex); putItemIntoBuffer(item); up(buffer_mutex); up(fillCount); }}procedure consumer() { while (true) { down(fillCount); down(buffer_mutex); item = removeItemFromBuffer(); up(buffer_mutex); up(emptyCount); consumeItem(item); }}
- monitor代码
monitor ProducerConsumer { int itemCount; condition full; condition empty; procedure add(item) { while (itemCount == BUFFER_SIZE) { wait(full); } putItemIntoBuffer(item); itemCount = itemCount + 1; if (itemCount == 1) { notify(empty); } } procedure remove() { while (itemCount == 0) { wait(empty); } item = removeItemFromBuffer(); itemCount = itemCount - 1; if (itemCount == BUFFER_SIZE - 1) { notify(full); } return item; }}procedure producer() { while (true) { item = produceItem(); ProducerConsumer.add(item); }}procedure consumer() { while (true) { item = ProducerConsumer.remove(); consumeItem(item); }}
2.代码实现
package com.fqyuan.blog;import java.util.LinkedList;import java.util.List;import java.util.Random;public class ListProducerConsumer { public static void main(String[] args) { ListProducerConsumerUtil.demonstrate(); }}class ListProducerConsumerUtil { public static void demonstrate() { SharedObjectList sharedObjectList = new SharedObjectList(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { sharedObjectList.produce(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { sharedObjectList.consume(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class SharedObjectList { private List<Integer> list = new LinkedList<>(); private final int LIMIT = 10; private Random random = new Random(); private Object lock = new Object(); private int cntValue = 0; public void consume() throws InterruptedException { while (true) { synchronized (lock) { while (list.size() == LIMIT) lock.wait(); list.add(cntValue++); lock.notify(); } Thread.sleep(random.nextInt(800)); } } public void produce() throws InterruptedException { while (true) { synchronized (lock) { while (list.size() == 0) lock.wait(); System.out.print("list size is " + list.size()); int value = ((LinkedList<Integer>) list).removeFirst(); System.out.println(", and removed value is: " + value); lock.notify(); } Thread.sleep(random.nextInt(1000)); } }}
运行结果:
list size is 1, and removed value is: 0list size is 1, and removed value is: 1list size is 1, and removed value is: 2list size is 1, and removed value is: 3list size is 2, and removed value is: 4list size is 2, and removed value is: 5list size is 3, and removed value is: 6list size is 2, and removed value is: 7list size is 2, and removed value is: 8list size is 3, and removed value is: 9list size is 2, and removed value is: 10list size is 1, and removed value is: 11list size is 2, and removed value is: 12list size is 1, and removed value is: 13list size is 2, and removed value is: 14list size is 4, and removed value is: 15list size is 3, and removed value is: 16list size is 5, and removed value is: 17list size is 7, and removed value is: 18list size is 6, and removed value is: 19list size is 7, and removed value is: 20list size is 6, and removed value is: 21list size is 6, and removed value is: 22list size is 7, and removed value is: 23list size is 7, and removed value is: 24
估计你也不想看这里.
- Multi-Programming-9 非线程安全类实现生产者和消费者
- Multi-Programming-8 线程安全类实现生产者和消费者
- 消费者和生产者问题的实现-基于线程安全的容器来和非线程安全的容器类
- 生产者和消费者线程实现
- 线程实现消费者和生产者机制
- 用生产者消费者模型实现的线程安全环形队列
- Java线程安全总结(包含生产者和消费者例子)
- 线程安全的消息排队机制和生产者消费者模型
- 生产者线程和消费者线程
- 一个可以重用的线程安全生产者消费者队列类
- c#线程实现生产者消费者
- 线程实现生产者消费者实验
- 线程中生产者和消费者
- 线程同步生产者和消费者c和java不同实现
- wait和notify实现的生产者消费者线程交互
- java实现线程同步一个生产者和一个消费者
- Java 实现生产者和消费者
- 生产者和消费者Java实现
- 《数据结构学习与实验指导》2-6:数列求和
- 如何将从数据库中读出的带有html标签的字符串,让标签起效,显示在前台页面
- FastDFS & Nginx install
- Maven的下载 安装 环境配置
- LINUX下实现sleep
- Multi-Programming-9 非线程安全类实现生产者和消费者
- #pragma warning 指令集
- Git使用详细教程
- ubuntu误删文件造成软件包信息列表损坏无法更新或安装文件
- 关于typeAliases标签理解 自己挖的坑啊,解决了好久的问题。
- 半夜三更搞不同长度字符对齐问题,头痛
- 1_字符设备驱动程序之LED驱动程序
- 蓝牙模块DIY A09 HC-05主从机一体蓝牙模块 无线蓝牙 串口透传
- 基于ConcurrentHashMap实现ConcurrentHashSet