生产者与消费者(二十五)

生产者与消费者(二十五)

在多线程的开发中,如果生产者创建资源的速度很快,而消费者消费的速度慢,这时生产者就要去等待消费者,这样会影响到处理的效率,反之亦然。为了处理这样的场景,我们需要准备一个缓冲区,即一个池子,生产者生产好后将资源存在缓冲区中,当缓存区满了就停止生产,消费者直接从缓存区中获取资源,当缓存区空了就停止消费,通知生产者生产。

生产者与消费者一般有两种实现方式,一种是管程法(即创建缓存区的方式),另一种是信号灯法(设置一个标识位实现)

管程法

例如,我们想要实现一个生产者生产汉堡,消费者消费汉堡的场景。在这个场景中我们有四个对象,生产者、消费者、汉堡和缓存区。

生产者

//生产者
class Productor implements Runnable{
    SynContainer synContainer;

    public Productor(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            Hamburger hamburger = new Hamburger(i);
            synContainer.push(hamburger);
            System.out.println("生产了第"+hamburger.id+"个汉堡");
        }
    }
}

消费者

//消费者
class Customer implements Runnable{
    SynContainer synContainer;

    public Customer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            Hamburger hamburder = synContainer.pull();
            System.out.println("消费了第"+hamburder.id+"个汉堡");
        }
    }
}

汉堡

//汉堡
class Hamburger {
    int id;

    public Hamburger(int id) {
        this.id = id;
    }
}

缓存区

//缓存区
class SynContainer {
    //一个可以存放10个汉堡的缓存区
    Hamburger[] hamburgers = new Hamburger[5];
    int count = 0;

    public synchronized void push (Hamburger hamburger) {
        //如果缓存区中数量为10,则不生产,同志消费者消费
        if (count == hamburgers.length) {
            try {
                System.out.println("缓存区已满,停止生产");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果缓存区中汉堡数量为0,则生产汉堡
        hamburgers[count] = hamburger;
        count++;
        this.notifyAll();
    }

    public synchronized Hamburger pull () {
        //如果缓存区中汉堡数量为0,则停止消费,呼叫生产者生产
        if (count == 0) {
            try {
                System.out.println("缓存区已空,停止消费");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果缓存区中汉堡数量>0,则消费汉堡
        Hamburger hamburger = hamburgers[count-1];
        count--;
        this.notifyAll(); //已经消费了,通知生产者可以生产了
        return hamburger;
    }
}

Main方法

public class GuanCheng {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        Productor productor = new Productor(container);
        Customer customer = new Customer(container);
        new Thread(productor).start();
        new Thread(customer).start();
    }
}

我们运行起来,看下结果,生产者将生产的汉堡存放在缓存区,消费者直接从缓存区中获取汉堡:

缓存区已空,停止消费
生产了第1个汉堡
生产了第2个汉堡
生产了第3个汉堡
生产了第4个汉堡
生产了第5个汉堡
生产了第6个汉堡
消费了第1个汉堡
缓存区已满,停止生产
消费了第6个汉堡
生产了第7个汉堡
消费了第7个汉堡
消费了第8个汉堡
生产了第8个汉堡
消费了第5个汉堡
消费了第9个汉堡
消费了第4个汉堡
消费了第3个汉堡
消费了第2个汉堡
缓存区已空,停止消费
生产了第9个汉堡
生产了第10个汉堡
消费了第10个汉堡

信号灯法

信号灯法就是设置一个标识位,当标识位flag位true时,进行生产;当标识位为false时,进行消费。

下面是一个红绿灯的例子,当标识位改变时,分别让行人和车辆通行。

package com.proandcum;

public class XinHao {
    public static void main(String[] args) {
        Road road = new Road();
        new Thread(new Car(road)).start();
        new Thread(new Walker(road)).start();
    }
}

class Car implements Runnable{
    Road rode;

    public Car(Road rode) {
        this.rode = rode;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            rode.drive();
        }
    }
}

class Walker implements Runnable{
    Road road;

    public Walker(Road road) {
        this.road = road;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            road.walk();
        }
    }
}

class Road {
    int carCount = 0;
    int walkerCount = 0;
    boolean flag = true;

    public synchronized void drive () {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("通过了第"+(++carCount)+"辆车");
        flag = !this.flag;
        this.notifyAll();
    }

    public synchronized void walk () {
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("通过了第"+(++walkerCount)+"个行人");
        flag = !this.flag;
        this.notifyAll();
    }
}

下面是代码运行起来的结果:

通过了第1辆车
通过了第1个行人
通过了第2辆车
通过了第2个行人
通过了第3辆车
通过了第3个行人
通过了第4辆车
通过了第4个行人
通过了第5辆车
通过了第5个行人
通过了第6辆车
通过了第6个行人
通过了第7辆车
通过了第7个行人
通过了第8辆车
通过了第8个行人
通过了第9辆车
通过了第9个行人
通过了第10辆车
通过了第10个行人

可以看到信号灯的改变依次让行人和车辆通行。

posted @ 2021-03-04 19:32  LucaZ  阅读(36)  评论(0编辑  收藏  举报