zoukankan      html  css  js  c++  java
  • 生产者消费者问题--synchronized

    # 代码

    public class App {
    
        public static void main(String[] args) {
    
            Depot depot = new Depot(100);
            Producer producer = new Producer(depot);
            Consumer consumer = new Consumer(depot);
    
            producer.produce(60);
            consumer.consume(100);
            producer.produce(90);
            consumer.consume(40);
    
        }
    }
    
    class Depot {
        // 仓库最大容量
        private int capacity;
        // 仓库目前容量
        private int size;
    
        public Depot(int capacity) {
            this.size = 0;
            this.capacity = capacity;
        }
    
        public synchronized void produce(int val) {
            try {
                int surplus = val;
                while (surplus > 0) {
                    while (size >= capacity) {
                        wait();
                    }
                    int incre = (size + surplus) > capacity ? (capacity - size) : surplus;
                    size += incre;
                    surplus -= incre;
                    System.out.printf("%s plan to produce (%d), actually produce (%d), depot size (%d) 
    ",
                            Thread.currentThread().getName(), val, incre, size);
                    notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void consume(int val) {
            try {
                int surplus = val;
                while (surplus > 0) {
                    while (size <= 0) {
                        wait();
                    }
                    int desc = (size < surplus) ? size : surplus;
                    size -= desc;
                    surplus -= desc;
                    System.out.printf("%s plan to consume (%d), actutally consume (%d), depot size (%d) 
    ",
                            Thread.currentThread().getName(), val, desc, size);
                    notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Producer {
        private Depot depot;
    
        public Producer(Depot depot) {
            this.depot = depot;
        }
    
        public void produce(final int val) {
            new Thread() {
                public void run() {
                    depot.produce(val);
                }
            }.start();
        }
    }
    
    class Consumer {
        private Depot depot;
    
        public Consumer(Depot depot) {
            this.depot = depot;
        }
    
        public void consume(final int val) {
            new Thread() {
                public void run() {
                    depot.consume(val);
                }
            }.start();
        }
    }

    # 输出:

    Thread-0 plan to produce (60), actually produce (60), depot size (60)
    Thread-3 plan to consume (40), actutally consume (40), depot size (20)
    Thread-2 plan to produce (90), actually produce (80), depot size (100)
    Thread-1 plan to consume (100), actutally consume (100), depot size (0)
    Thread-2 plan to produce (90), actually produce (10), depot size (10)

    # 有四个线程参与了这个过程,两个生产者,两个消费者


    # 时隔多月,我们再来考虑一种业务场景,假设要求是,生产的时候的条件是:要么全部生产,要么全部不生产;消费的条件也是:要么全部消费,要么不消费;此时,实现的代码可能如下:

    public class Common {
    
        public static void main(String[] args) {
            Depot depot = new Depot(100);
            Producer producer = new Producer(depot);
            Consumer consumer = new Consumer(depot);
    
            for (int i = 0; i < 10; i++) {
                producer.produce(50);
            }
    
            for (int i = 0; i < 50; i++) {
                consumer.consume(10);
            }
    
        }
    }
    
    class Depot {
        // 仓库最大容量
        private int capacity;
        // 仓库目前容量
        private int size;
    
        public Depot(int capacity) {
            this.size = 0;
            this.capacity = capacity;
        }
    
        public synchronized void produce(int val) {
            try {
                if (size + val > capacity) {
                    wait();
                }
                size += val;
                System.out.printf("%s produce (%d), depot size (%d) 
    ", Thread.currentThread().getName(), val, size);
                notifyAll();
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void consume(int val) {
            try {
                if (size - val < 0) {
                    wait();
                }
                size -= val;
                System.out.printf("%s consume (%d), depot size (%d) 
    ", Thread.currentThread().getName(), val, size);
                notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Producer {
        private Depot depot;
    
        public Producer(Depot depot) {
            this.depot = depot;
        }
    
        public void produce(final int val) {
            new Thread() {
                public void run() {
                    depot.produce(val);
                }
            }.start();
        }
    }
    
    class Consumer {
        private Depot depot;
    
        public Consumer(Depot depot) {
            this.depot = depot;
        }
    
        public void consume(final int val) {
            new Thread() {
                public void run() {
                    depot.consume(val);
                }
            }.start();
        }
    }

      - 运行一下,你会发现仓库中的数量会出现负的情况,如果你改变生产者和消费者的线程数,还有可能出现超过仓库容量的情况,这该怎么解决呢?

      - 其实解决方法很简单,把wait()方法的判断语句由if换成while即可;

      - 我们来深究原因,以消费者为例,if的情况下,消费线程由wait状态切换到运行状态的时候,不再去判断仓库中的现有的存储量是否满足消费,此时该消费线程有可能由其他的消费线程唤醒,而其他的线程早已经把仓库消费完了,该线程再去消费,仓库自然就变成负的了。而while则不同,判断条件为while时,每次消费者线程被唤醒,均会做一次判断。

      - 其实在jdk文档中,对这种情况已经作了强调说明, 如下图所示

     ! 多读官方文档,多读源码!  手动笑哭。。。

  • 相关阅读:
    Java实现 LeetCode 416 分割等和子集
    Java实现 LeetCode 416 分割等和子集
    在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)
    【详解】嵌入式开发中固件的烧录方式
    嵌入式系统烧写uboot/bootloader/kernel的一般方法
    Linux下USB烧写uImage kernel
    Xmanager连接CentOS的远程桌面
    命令行利器Tmux
    u-boot中分区和内核MTD分区关系
    uboot环境变量与内核MTD分区关系
  • 原文地址:https://www.cnblogs.com/lwmp/p/11512636.html
Copyright © 2011-2022 走看看