生产者和消费者问题(java简单实现)

生产者消费者问题(百度百科):生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

简单来说:按照通俗理解,我们可以想象,有一个商店仓库,可以存放的商品数量有限,制作商品的厂家(生产者)不停的将生产的商品运送到商店仓库,当商店仓库满了,厂家停止运送商品,进入停工状态。购买者(消费者)可以不停的购买商品仓库的商品,如果仓库没有商品可购买,购买者停止商品。厂家处于停工状态时需得到消费者购买掉商品的信息后,则可继续运送。购买者在无商品可买的状态下需要得到厂家已运送商品的信息后,可继续购买。

怎么知道仓库当前商品的数量呢?是否空或者是否满呢?很容易,数一下当前仓库的商品数量就行了,如果数量为0,那么仓库无货,消费者无法购买,如果数量达到仓库的容量最大值,那么仓库已满,生产者无法继续运送商品进入仓库。

由于厂家和购买者的动作时同时进行,这里容易出现问题,如果在同一时刻有一个商品进又有一个商品出,显然时无法判断仓库商品数量的,这是一个临界问题,宏观上理解就是,如果在一个教室两条门, 在有人同时进门和出门时,你无法判断教室里人的个数一样。在进教室和出教室必须有一个先后关系,也就是在同一时刻,只能有一个人进了教室,或者一个人出了教室。

所以,在java实现生产者和消费者问题时,自然而然用到了synchronized这个关键字,利用它控制生产者和消费者线程在并行状态下,在同一时刻,只能有一个线程操作仓库资源。

知道原理之后,代码就容易写了!

生产者线程代码:

import java.util.*;

public class Producer extends Thread{
    //list仓库资源,消费者和生产者线程共享
    private List<Integer> list;
    private int max;//仓库能容纳资源最大数量

    public Producer(String name,int max,List<Integer> list){
        super(name);
        this.max=max;
        this.list=list;
    }
    public void run(){
        while(true){
            //加锁,限制在同一时刻只能有同一个线程操作仓库的资源
            synchronized(list){
                //如果仓库资源满了,生产者无法继续生产资源,则让生产者线程等待
                while(list.size()==max){
                    System.out.println("仓库满了!");
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                //随机生成一个1-100的数字添加进仓库资源
                int num=(int)(Math.random()*100)+1;
                list.add(num);
                System.out.println(this.getName()+"生产了"+num);
                list.notify();//唤醒等待的消费者进程
            }
        }
    }

}

消费者线程代码:

import java.util.List;

public class Consumer extends Thread{
    //list表示仓库资源
    private List<Integer> list;
    private int max;//设置仓库最大容量
    //消费者构造函数
    public Consumer(String name,int max,List<Integer> list){
        super(name);
        this.max=max;
        this.list=list;
    }
    public void run(){
        while(true){
            //list是公用资源
            synchronized(list){
                //如果仓库资源为空,消费者无法获取资源,则让消费者线程等待
                while(list.isEmpty()){
                    System.out.println("仓库空了");
                    try {
                        list.wait();//线程等待
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                //否则执行消费动作
                System.out.println(this.getName()+"正在消费"+list.get(list.size()-1));
                list.remove(list.size()-1);//消费掉list仓库的尾部一个资源
                list.notify();//唤醒其他所有线程
            }
        }
    }
}

测试代码:

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args){
        List<Integer> list =new ArrayList<Integer>();
        int max=10;
        Producer p=new Producer("生产者",max,list);
        Consumer c=new Consumer("消费者",max,list);
        p.start();//开启生产者线程
        c.start();//开启消费者线程
    }
}

代码中设计的wait()和notify()方法说明:
不是thread方法,而是Object方法
wait():当前线程获取对象的锁后,才调用该对象的wait方法的。调用后,该对象的等待队列中就有了一个所在线程,那个线程进入等待状态,此时,只有该对象调用notify方法,才可以把那个线程从队列里面拿出来,使这个线程成为可运行线程。
notify():唤醒线程等待队列中的线程。由于这个程序中只有生产者和消费者两个线程,所以使用notify唤醒线程没问题。
如果线程等待队列中有多个线程,则采用notifyAll()方法唤醒所有等待线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值