zoukankan      html  css  js  c++  java
  • Java提高——多线程(五)生产消费者问题

    生产者/消费者问题是个典型的多线程问题,类似于hello world对于一门编程语言而言,涉及的对象包括“生产者”、“消费者”、“仓库”和“产品”。

    该模型需要注意以下几点:

    1、生产者只有在仓库未满的时候生产,仓满则停止生产。

    2、消费者只有在仓库有产品的情况下才能消费,空仓则等待。

    3、当消费者发现没有产品时通知生产者生产。

    4、生产者在生产出可消费的产品时,通知等待的消费者去消费。

    此模型需要结合Object类的wait、notify、notifyAll方法。

    package Progress.Thread;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Proxy;
    
    /**
     * @date 2018/5/4 16:07
     * 消费者/生产者问题
     */
    public class Test {
        public static void main(String[] args) {
            Godown godown = new Godown(100);
            Producer pro = new Producer(godown);
            Consumer con = new Consumer(godown);
    
            pro.produce(60);
            pro.produce(120);
            con.consume(90);
            con.consume(150);
            con.consume(110);
        }
    }
    /**仓库*/
    class Godown extends Thread{
        /**仓库容量*/
        private int capacity;
        /**仓库的实际容量*/
        private int size;
    
        public Godown() {
        }
    
        public Godown(int capacity) {
            this.capacity = capacity;
            this.size = 0;
        }
    
        public synchronized void produce(int value){
            //value表示想要生产的数量(有可能生产量太多需要多次生产)
            try {
                while (value>0){
                    //库存满的时候等待消费者消费产品
                    while (size>=capacity) {
                        wait();
                    }
                        //获取实际生产的数量(即库存中增加的数量)
                        //如果 库存+想要生产的数量>总的容量,则 实际增量=总的容量-实际容量(此时仓库满仓)
                        //否则 实际增量=想要生产的数量
                        int increment = (size+value)>capacity ? capacity - size : value;
                        size = size + value;
                        value -= increment;
                        System.out.println(Thread.currentThread()+" "+getName()+" "+value+" "+size+" "+increment);
                        //System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d
    ",
                        //Thread.currentThread().getName(), increment, size,value);
    
                        //通知消费者消费
                        notifyAll();
    
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void consume(int value){
            try {
                //value表示要消费的数量(可能消费量太大数量不够,要多次提供以供消费)
                while (value>0){
                    //库存为0时,等待生产者生产
                    while (size<=0) {
                        wait();
                    }
                        //获取实际消费的数量,即库中实际减少的量
                        //如果 库存<要消耗的量,则 实际消耗量 = 库存
                        //否则,实际消耗的量 = 要消耗的量
                        int decent = size<value?size:value;
                        size -= decent;
                        value -= decent;
                        System.out.println(Thread.currentThread()+" "+getName()+" "+value+" "+size+" "+decent);
                        //System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d
    ",
                        //Thread.currentThread().getName(), decent,value, size);
                        //通知生产者生产
                        notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public String toString() {
            return "Godown{" +
                    "capacity=" + capacity +
                    ", size=" + size +
                    '}';
        }
    }
    /**生产者*/
    class Producer extends Thread{
        private Godown godown;
    
        public Producer(Godown godown) {
            this.godown = godown;
        }
    
        //新建一个线程向仓库中生产产品
        public void produce(final int val){
            new Thread(){
                @Override
                public void run(){
                    godown.produce(val);
                }
            }.start();
        }
    }
    
    /**消费者*/
    class Consumer extends Thread{
        private Godown godown;
    
        public Consumer(Godown godown) {
            this.godown = godown;
        }
    
        //新建一个线程去消耗产品
        public void consume(final int val){
            new Thread(){
                @Override
                public void run(){
                    godown.consume(val);
                }
            }.start();
        }
    }
    

    生产者与仓库关联,当调用produce方法时,会生成一个线程向仓库中生产产品。

    消费者与仓库关联,当调用consume方法时,会生成一个线程从仓库中获得商品用于消费。

    produce方法和consume方法都是synchronized的意味着进入就会获得仓库对象的同步锁。也就是说同一时间,生产者和消费者线程只能有一个能够运行,另一个必须等待,通过同步锁实现了对“残酷”的互斥访问。

    produce方法:当仓库满时,生产者线程等待,等待消费者消费商品之后,生产者才生产;生产之后通过notifyAll唤醒同步锁上的所有线程,包括消费者线程,“通知消费者消费”

    consume方法:当空仓的时候,消费者等待,等待生产者生产商品之后,消费者才消费;消费者通过notifyAll唤醒同步锁上的所有线程,包括生产者线程,“通知生产者生产”

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3480016.html

  • 相关阅读:
    素材收集
    网站返回503
    uva 1048 最短路的建图 (巧,精品)
    hdu5188 01 背包
    hdu 5187 快速幂 + 快速乘 值得学习
    差分约束
    uva11090 Bellman-Ford 运用
    hdu 5185 动态规划 分析降低复杂度
    hdu5184 数论证明
    HDU5183 hash 表
  • 原文地址:https://www.cnblogs.com/huangzhe1515023110/p/9276093.html
Copyright © 2011-2022 走看看