Java多线程--生产者消费者模型(Semaphore实现)

需求

要求:使用2个线程,分别代表:生产者、消费者。让他们并发的去生产、消费产品。生产的总数是不能超过N的。

实现思路

这里我们使用的是使用信号量去控制线程的生产消费,通过释放令牌的形式去控制生产者消费者的上限。使用互斥锁保证每次最多只有一个角色去修改共享变量。来看张图,一图胜千言。
这里写图片描述

代码实现

代码的注释写的挺详细了,可以仔细阅读一下,若有不懂或者写错的地方欢迎留言。

package model;


import java.util.concurrent.Semaphore;

import static java.lang.System.out;

/**
 * Created by lewis on 2017/4/11.
 *
 * 生产者消费者模型
 *
 */
public class ProducerConsumerProblem{

    //初始容量
     private static final int N = 10;

    /***
     * full 产品容量
     * empty 空余容量
     * mutex 读写锁
     */
    private static Semaphore full,empty,mutex;
    //记录当前的产品数量
     private static volatile int count = 0 ;

     static {
         /**
          * full 初始化0个产品
          * empty 初始化有N个空余位置放置产品
          * mutex 初始化每次最多只有一个线程可以读写
          * */
         full = new Semaphore(0);
         empty = new Semaphore(N);
         mutex = new Semaphore(1);
     }


    public static void main(String []args){
         //生产线线程
        new Thread(new Producer()).start();
        //消费者线程
        new Thread(new Consumer()).start();
    }

    //生产者类
    static class Producer implements Runnable{

        @Override
        public void run() {
            while (true){
                try {
                    empty.acquire();//等待空位
                    mutex.acquire();//等待读写锁
                    count++;
                    out.println("生产者生产了一个,还剩:"+count);
                    mutex.release();//释放读写锁
                    full.release();//放置产品
                    //随机休息一段时间,让生产者线程有机会抢占读写锁
                    Thread.sleep(((int)Math.random())%10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //消费者类
    static class Consumer implements Runnable{

        @Override
        public void run() {
            while (true){
                try {
                    full.acquire();//等待产品
                    mutex.acquire();//等待读写锁
                    count--;
                    out.println("消费者消费了一个,还剩:"+count);
                    mutex.release();//释放读写锁
                    empty.release();//释放空位
                    //随机休息一段时间,让消费者线程有机会抢占读写锁
                    Thread.sleep(((int)Math.random())%10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

最后的闲话

其实最近操作系统在教多线程的经典的一些模型,于是打算使用java把这些模型都实现一遍。今天写的是生产者消费者模型。
其实自己开始写这个模型,发现下课后就老师讲的忘了。。。。结果想了好久,未果。于是去翻课件,看了一下伪代码,查了些API才写出来。就这样吧,如若写错欢迎纠错指正。

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
生产者消费者模型是计算机科学中一个经典的问题,也是进程同步与互斥的一个重要应用。该模型描述了一个生产者和一个消费者共同使用一个有限缓冲区的情景,生产者向缓冲区中添加数据,而消费者则从缓冲区中取出数据。 为了避免在共享缓冲区时产生数据不一致的情况,需要进行进程同步和互斥。其中,进程同步是指在多个进程之间协调事件发生的时间,而互斥则是指在同一时间只允许一个进程访问共享资源。 以下是一个基于信号量的生产者消费者模型的示例: ```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; // 消费者读取数据的位置 sem_t empty; // 信号量,表示缓冲区中空余的位置数 sem_t full; // 信号量,表示缓冲区中已有数据的位置数 sem_t mutex; // 信号量,用于实现互斥访问缓冲区 void *producer(void *arg) { int item; while(1) { item = rand() % 1000; // 生产者随机生成一个数据项 sem_wait(&empty); // 等待缓冲区有空余位置 sem_wait(&mutex); // 进入互斥区,保证对缓冲区的访问是互斥的 buffer[in] = item; printf("Producer produces item %d at buffer[%d]\n", item, in); in = (in + 1) % BUFFER_SIZE; sem_post(&mutex); // 退出互斥区 sem_post(&full); // 增加已有数据的位置数 sleep(rand() % 2); // 生产者随机休眠一段时间 } } void *consumer(void *arg) { int item; while(1) { sem_wait(&full); // 等待缓冲区有数据 sem_wait(&mutex); // 进入互斥区 item = buffer[out]; printf("Consumer consumes item %d from buffer[%d]\n", item, out); out = (out + 1) % BUFFER_SIZE; sem_post(&mutex); // 退出互斥区 sem_post(&empty); // 增加空余位置数 sleep(rand() % 2); // 消费者随机休眠一段时间 } } int main() { pthread_t producer_thread, consumer_thread; sem_init(&empty, 0, BUFFER_SIZE); // 初始化信号量 sem_init(&full, 0, 0); sem_init(&mutex, 0, 1); pthread_create(&producer_thread, NULL, producer, NULL); // 创建生产者线程 pthread_create(&consumer_thread, NULL, consumer, NULL); // 创建消费者线程 pthread_join(producer_thread, NULL); // 等待生产者线程结束 pthread_join(consumer_thread, NULL); // 等待消费者线程结束 sem_destroy(&empty); // 销毁信号量 sem_destroy(&full); sem_destroy(&mutex); return 0; } ``` 在上述代码中,empty 表示缓冲区中空余的位置数,初始值为 BUFFER_SIZE;full 表示缓冲区中已有数据的位置数,初始值为 0;mutex 用于实现互斥访问缓冲区,初始值为 1。在生产者和消费者访问缓冲区时,都需要先进行信号量操作,保证进程同步和互斥。其中,sem_wait 和 sem_post 分别表示等待和增加信号量的值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值