生产者与消费者问题

***********************************************声明******************************************************

      原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

      由于各种原因,可能存在诸多不足,欢迎斧正!

*********************************************************************************************************

     在进行多线程编程的过程中,线程间的同步与互斥是件需要认真考虑的关键点,而生产者与消费者就是线程间同步的典型例子:若干个生产者在生产产品,若干个消费者同时消费这些物品,保证多个生产者和多个消费者能并发或并行(关于并行与并发的区别以及多线程编程的一些基本概念,可以参考这篇博文:多线程初步)执行。解决生产者与消费者的典型方法是设立一个产品缓冲区,然后多个生产者与消费者互斥的访问该缓冲区。 

1、模型分析

     生产者与消费者问题本质上是一个同步与互斥问题,其需要注意的地方总结出来有两点:

1)、同步:当缓冲区不满时生产者线程可以继续执行,生产者执行的结果是向缓冲区添加产品;缓冲区不空时消费者线程可以继续执行,消费者执行的结果是从缓冲区取出产品。生产者与消费者可以相互穿插地执行,提高系统效率,还原情景真实性。

2)、互斥:由于生产者与消费者都可以改变缓冲区的状态,所以对缓冲区的操作应该互斥地进行,即不能同时读取相同的变量,避免发生读写冲突。

    由于缓冲区的大小设定、生产者与消费者的数量都会影响该类问题的难度。在此为了简化起见,假定生产者与消费者都顺序操作缓冲区的产品。

2、源代码

/**
 *    ProducerAndConsumer.java
 *    Copyright 2014.11.1 XuJin
 **/
import java.util.ArrayList;
import java.util.List;

class ProductBuffer {
	private List<Integer> m_listProduct = new ArrayList<Integer>();
	private int m_nSize;

	public ProductBuffer(int size) {
		m_nSize = size;
		m_listProduct.clear();

	}

	synchronized int get() {
		while (m_listProduct.size() <= 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println(e);
			}
		}
		int retValue = m_listProduct.get(m_listProduct.size() - 1);
		m_listProduct.remove(m_listProduct.size() - 1);
		notifyAll();
		return retValue;
	}

	synchronized void put(int mon) {
		while (m_listProduct.size() >= m_nSize) {
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println(e);
			}
		}
		m_listProduct.add(mon);
		notifyAll();
	}
}

class Producer extends Thread {
	private ProductBuffer m_Product;
	private int m_nValue;

	Producer(ProductBuffer pro, int value) {
		m_Product = pro;
		m_nValue = value;
	}

	public void run() {
		m_Product.put(m_nValue);
		System.out.println("生产者中 product为 " + m_nValue);
		try {
			sleep(100);
		} catch (InterruptedException e) {
			System.out.println(e);
		}
	}
}

class Consumer extends Thread {
	private ProductBuffer m_Product;

	Consumer(ProductBuffer pro) {
		m_Product = pro;
	}

	public void run() {
		int val = m_Product.get();
		System.out.println("消费者中 product为 " + val);
	}
}

public class ProducerAndConsumer {
	public static void main(String[] agr) {
		ProductBuffer pro = new ProductBuffer(10);
		Producer[] myPro = new Producer[10];
		for (int i = 0; i < 10; ++i) {
			myPro[i] = new Producer(pro, i);
		}
		Consumer[] myCon = new Consumer[10];
		for (int i = 0; i < 10; ++i) {
			myCon[i] = new Consumer(pro);
		}

		for (int i = 0; i < 10; ++i) {
			myPro[i].start();
			myCon[i].start();
		}
	}
}
      上述代码的功能实现了多个生产者与多个消费者的同步与互斥问题,但生产者与生产者、生产者与消费者、消费者与消费者之间不同同时访问缓冲区,这点是有别于读者与写者问题的。

3、注意事项

1)、JAVA集合只能存放引用类型的的数据,不能存放基本数据类型 ,所以如下的代码段是有错的:

private List<int> m_listProduct = new ArrayList<int>();

应该为:

private List<Integer>  m_listProduct = new ArrayList<Integer>();

2)、synchronized的使用

      synchronized可用于锁定一个对象或一个方法,声明任何时候只能有一个线程访问其所修饰的一段代码块或一个方法,另外线程可以访问没被声明为synchronized的代码块或方法。在Java中,不仅类实例对象可以用修饰synchronized,类本身也对应一把锁用修饰synchronized,即类的静态成员函数声明为synchronized,以控制其对类的静态成员变量的访问。synchronized 方法的缺陷:若将一个大的方法声明为synchronized将会大大影响效率,可以通过尽可能的缩小synchronized修饰的段代码范围来提高效率。

3)、wait()、notifyAll()方法的使用

      在Java中,notifyAll、wait方法继承自所有类共有的基类Object。

A、wait()

     导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。

B、notifyAll()

     唤醒在此对象监视器上等待的所有线程,线程通过调用其中一个wait 方法,在对象的监视器上等待。

A、有synchronized的地方不一定有wait(),notify()
B、有wait(),notify()的地方必有synchronized。因为wait()和notify()不是属于线程类,而是每一个对象都具有的方法,而且,这两个方法都和对象锁有关,有锁的地方,必有synchronized。


    由于时间有限,在写博文的过程中参考过一些文献,在此表示感谢;同时鉴于水平原因,你难免有不足之处,欢迎斧正!


                          

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生产者消费者问题可以使用线程和信号量来实现。 以下是一个简单的C语言程序,使用互斥锁和条件变量来解决生产者消费者问题: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int in = 0; int out = 0; pthread_mutex_t mutex; sem_t empty; sem_t full; void* producer(void* arg) { int item; while (1) { item = rand(); sem_wait(&empty); pthread_mutex_lock(&mutex); buffer[in] = item; in = (in + 1) % BUFFER_SIZE; printf("Produced item: %d\n", item); pthread_mutex_unlock(&mutex); sem_post(&full); } } void* consumer(void* arg) { int item; while (1) { sem_wait(&full); pthread_mutex_lock(&mutex); item = buffer[out]; out = (out + 1) % BUFFER_SIZE; printf("Consumed item: %d\n", item); pthread_mutex_unlock(&mutex); sem_post(&empty); } } int main() { pthread_t tid1, tid2; pthread_mutex_init(&mutex, NULL); sem_init(&empty, 0, BUFFER_SIZE); sem_init(&full, 0, 0); pthread_create(&tid1, NULL, producer, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(&mutex); sem_destroy(&empty); sem_destroy(&full); return 0; } ``` 在该程序生产者线程和消费者线程无限循环地执行。生产者线程生成一个随机数并将其放入缓冲区,然后唤醒消费者线程。消费者线程从缓冲区获取一个项目并打印出来,然后唤醒生产者线程。 互斥锁用于保护缓冲区的读写操作,而信号量则用于控制缓冲区的空闲和已用空间。当缓冲区已满时,生产者线程被阻塞在 sem_wait(&empty) 处,直到有空间可用。当缓冲区为空时,消费者线程被阻塞在 sem_wait(&full) 处,直到有项目可用。 注意,该程序仅为示例,实际应用可能需要更复杂的同步机制和错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值