记录Java线程模拟生产者——消费者模式

生产者——消费者

生产者消费者模式 :不属于设计模式 只是线程之间通信的一种场景

生产什么消费什么

没有生产 不能消费

不能重复消费同一个产品

保证产品的完整性

例子——电脑购买练习代码

电脑类:

public class Computer {
    private String mainFrame;
    private String screen;

    // false 可以生产 不能消费
    // true 可以消费 不能生产
    private boolean flag; // 是否可以生产/消费的牌子

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public String getMainFrame() {
        return mainFrame;
    }

    public void setMainFrame(String mainFrame) {
        this.mainFrame = mainFrame;
    }

    public String getScreen() {
        return screen;
    }

    public void setScreen(String screen) {
        this.screen = screen;
    }

    public Computer() {
    }

    public Computer(String mainFrame, String screen) {
        this.mainFrame = mainFrame;
        this.screen = screen;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "mainFrame='" + mainFrame + '\'' +
                ", screen='" + screen + '\'' +
                '}';
    }
}

生产者:

public class Producer extends Thread{
    private Computer computer;

    public Producer(Computer computer) {
        this.computer = computer;
    }

    @Override
    public void run() {
        for(int i = 1;i <= 20;i++){
            synchronized (computer) {
                if(computer.isFlag() == true){
                    try {
                        computer.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(i % 2 != 0){
                    computer.setMainFrame(i + "号联想主机");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    computer.setScreen(i + "号联想显示器");
                    System.out.println("生产了" + i + "号联想电脑");
                }else{
                    computer.setMainFrame(i + "号华硕主机");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    computer.setScreen(i + "号华硕显示器");
                    System.out.println("生产了" + i + "号华硕电脑");
                }
                computer.setFlag(true);
                computer.notify();
            }
        }
    }
}

消费者:

public class Consumer extends Thread {
    private Computer computer;

    public Consumer(Computer computer) {
        this.computer = computer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            synchronized (computer) {
                while (true) {
                    if (computer.getFlag() == 0 || computer.getFlag() == 1) {
                        try {
                            computer.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        break;
                    }
                }

                System.out.println("消费了第" + i + "号" + computer);

                computer.setFlag(0);
                computer.notifyAll();
            }
        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer();

        Producer producer = new Producer(computer);
        Consumer consumer = new Consumer(computer);

        producer.setName("生产者");
        consumer.setName("消费者");

        producer.start();
        consumer.start();
    }
}

以上实现效果为:生产一个就消费一个,自然不太符合现实生活,后续会利用队列来真实地模拟出符合现实生活的操作(~ ̄▽ ̄)~

改写代码

( •̀ ω •́ )✧心潮澎湃下,小编突然觉得两个线程还是有些单调了,众所周知,生厂商和消费者中间可以有一个线上 / 线下店铺,那是不是也可以将其当作一个进程呢?
于是,我在原基础上改写了一下,代码如下:
电脑类:

public class Computer {
    private String mainFrame;
    private String screen;

    //0,表示可以生产,不能进货,不能消费
    //1,表示不能生产,可以进货,但处于进货中,不能消费
    //2,表示不能生产,不能进货,但已经进完货,可以消费
    private int Flag;

    public Computer() {
    }

    public Computer(String mainFrame, String screen) {
        this.mainFrame = mainFrame;
        this.screen = screen;
    }

    public String getMainFrame() {
        return mainFrame;
    }

    public void setMainFrame(String mainFrame) {
        this.mainFrame = mainFrame;
    }

    public String getScreen() {
        return screen;
    }

    public void setScreen(String screen) {
        this.screen = screen;
    }

    public int getFlag() {
        return Flag;
    }

    public void setFlag(int flag) {
        Flag = flag;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "mainFrame='" + mainFrame + '\'' +
                ", screen='" + screen + '\'' +
                ", Flag=" + Flag +
                '}';
    }
}

生产者:

public class Producer extends Thread {
    private Computer computer;

    public Producer(Computer computer) {
        this.computer = computer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            synchronized (computer) {
                while (true) {
                    if (computer.getFlag() == 1 || computer.getFlag() == 2) {
                        try {
                            computer.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        break;
                    }
                }


                if (i % 2 != 0) {
                    computer.setMainFrame(i + "号联想主机");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    computer.setScreen(i + "号联想显示器");
                    System.out.println("生产了" + i + "号联想电脑");
                } else {
                    computer.setMainFrame(i + "号华硕主机");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    computer.setScreen(i + "号华硕显示器");
                    System.out.println("生产了" + i + "号华硕电脑");
                }

                computer.setFlag(1);
                //这里为何是computer.notify()?
                computer.notifyAll();
            }
        }
    }
}

消费者:

public class Consumer extends Thread {
    private Computer computer;

    public Consumer(Computer computer) {
        this.computer = computer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            synchronized (computer) {
                while (true) {
                    if (computer.getFlag() == 0 || computer.getFlag() == 1) {
                        try {
                            computer.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        break;
                    }
                }

                System.out.println("消费了第" + i + "号" + computer);

                computer.setFlag(0);
                computer.notifyAll();
            }
        }
    }
}

商店:

public class Store extends Thread {
    private Computer computer;

    public Store(Computer computer) {
        this.computer = computer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            synchronized (computer) {
                while (true) {
                    if (computer.getFlag() == 0 || computer.getFlag() == 2) {
                        try {
                            computer.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        break;
                    }
                }


                System.out.println("进货了第" + i + "号" + computer);

                computer.setFlag(2);
                computer.notifyAll();
            }
        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer();

        Producer producer = new Producer(computer);
        Consumer consumer = new Consumer(computer);
        Store store = new Store(computer);

        producer.setName("生产者");
        store.setName("电脑商店");
        consumer.setName("消费者");

        producer.start();
        store.start();
        consumer.start();
    }
}

问题解答

(●ˇ∀ˇ●)心细的读者可能发现了,Flag判断又原本的一层变成了多层,这与线程运行和父类提供的方法有关。

起初,当生产者线程执行时,商店线程和消费者线程则进入休眠状态,即wait(),当生产者唤醒所有程序时,商店线程和消费者线程都会被唤醒。

然而生产者线程执行完后,下一个线程并不一定是商店线程,也可能是消费者线程。

除外,读者可能也有些疑惑了,为啥代码中调用的是唤醒所有线程 notifyAll() 方法,而不是只会唤醒一个线程的 notify() 方法,亦或者直接指向商店线程呢?

众所周知,线程的执行先后顺序,不是由线程决定的,是由CPU决定的。

ψ(`∇´)ψ正如爱情公寓张伟所说:“拿什么和你赌不是看你要什么,而是看我有什么!”

Alt
于是,无论是被唤醒的商店线程或消费者线程,都会从 wait() 后面代码执行,并不会再次进入判断 if

那怎么办呢?增加多一层相同判断 if

开始时我也是这样想的,并为每个线程增加了一层相同判断 if,控制台输出的结果也达到了小编的期待,但在小编手贱重复运行整个程序时,Σ(っ °Д °;)っ竟意外发现有小概率打印的结果会乱序。

然而,赶去厕所的路上,我突然想到,如果两个线程要一层判断 if,三个线程要两层判断** if ,那 n 个线程岂不是要 n-1 个判断 if **?

于是在o( ̄▽ ̄)ブ厕所之神的帮助下,我灵光一闪,想到了利用循环判断来解决该问题。

正如网络名言“ 如果一发导弹不能杀死敌人,那就两发,如果两发还不够就三发!”ヾ(≧▽≦*)o

最后,如果大家还要增加多个线程的话,可以将判断条件改简洁点,毕竟优秀的程序员是不会让代码繁乱的○( ^皿^)っHiahiahia…

备注:大神看了觉得还能再简洁或者有更强的操作可以在私聊我,亦或评论区评论下!
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值