生产者消费者问题--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) \n",
                        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) \n",
                        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) \n", 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) \n", 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文档中,对这种情况已经作了强调说明, 如下图所示

 

 

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

posted on 2019-09-12 16:37  斜月三星一太阳  阅读(330)  评论(0编辑  收藏  举报