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

来源:互联网 发布:seo软文免费发布渠道 编辑:程序博客网 时间:2024/06/07 19:09

生产者消费者问题(百度百科):生产者消费者问题(英语: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
原创粉丝点击