生产者/消费者 - synchronized,condition

一、今天用synchronized实现了下生产者/消费者模式,遇到几个小问题,记录下。

public class SynchronizedDemo {

    //类似包子铺场景:包子最多提前做好50个,卖出去5个就再做;卖完了,买包子的就得等着
    //Synchronized版本

    private static int MAX = 50;
    private int number = 0;

    public void produce() throws InterruptedException {
        while (true) {
            synchronized (this) {
                if (number == MAX) {
                    //释放锁,出让cpu时间片,线程状态 - WAITING,等待唤醒
                    this.wait();
                    continue;
                }
                number++;
                System.out.println("+++++第 " + number + " 个包子被做出来了! - " + Thread.currentThread().getName());
                if (number > 20) {
                    //做出包子超过20个,买包子的赶紧买
                    this.notifyAll();
                }
            }
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            synchronized (this) {
                if (number == 0) {
                    //释放锁,出让cpu时间片,线程状态 - WAITING,等待唤醒
                    this.wait();
                    continue;
                }
                System.out.println("-----第 " + number + "个包子被买了! - " + Thread.currentThread().getName());
                number--;
                if (number < MAX - 5) {
                    //包子空缺超过5个,通知做包子的赶紧做
                    this.notifyAll();
                }
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        //5个做包子的
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    synchronizedDemo.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        //20个买包子的
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                try {
                    synchronizedDemo.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

produce()和consume()方法中在调用 this.wait() 后,之前手快写了个return。。。

排查了半天,重走了下逻辑才发现。
排查过程中,理解了下 return 和不启用 notifyAll() 的线程统计。

1. return + 启用notifyAll()

此时对应线程就结束了,会看到有几个线程(4-5个)处于WAITING状态。

2. continue + 不启用 notifyAll()

所有线程最终都会进入WAITING状态。

 

二、Condition

public class ConditionDemo {

    //类似包子铺场景:包子最多提前做好10个,少于10个就再做;卖完了,买包子的就得等着
    //Condition版本
    private final int MAX = 10;
    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition full = lock.newCondition();//满状态条件
    Condition empty = lock.newCondition();//空状态条件

    public void produce() throws InterruptedException {
        lock.lock();
        if (number == MAX) {
            full.await();
            return;
        }
        //生产者再生产
        System.out.println("+++++第 " + ++number + " 个包子被做出来了!" + Thread.currentThread().getName());
        if (number >= 5) {
            //生产出至少5个包子,通知赶紧买包子
            empty.signalAll();
        }
        lock.unlock();
    }

    public void consume() throws InterruptedException {
        lock.lock();
        if (number == 0) {
            empty.await();
            return;
        }
        //消费者再消费
        System.out.println("-----第 " + number-- + " 个包子被买了!" + Thread.currentThread().getName());
        if (number <= MAX - 5) {
            //剩余包子不足,赶紧生产
            full.signalAll();
        }
        lock.unlock();
    }

    public static void main(String[] args) {
        ConditionDemo conditionDemo = new ConditionDemo();
        //5个做包子的
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        conditionDemo.produce();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        //20个买包子的
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                while (true) {
                    try {
                        conditionDemo.consume();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

 

posted on 2022-05-14 12:26  -赶鸭子上架-  阅读(40)  评论(0编辑  收藏  举报