生产者消费者模式

生产者消费者模式

生产者消费者模式是线程协作的一种情况,意思是线程1生产资源,线程2消费资源,有资源时才能消费,没有资源时需要生产。

运作生产者消费者模式有两种办法:管程法和信号灯法。

管程法

管程法建造一个缓冲区,让生产者生产的资源存储在缓冲区,消费者从缓冲区中获取资源,而不是直接从生产者那里获取。

以下代码演示管程法:

package com.cxf.multithread.produce_consume;

import java.awt.*;

public class TestForProduceConsume {
    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        new Producer(buffer).start();
        new Consumer(buffer).start();
    }
}

class Producer extends Thread {
    Buffer buffer;
    public Producer(Buffer buffer) {
        this.buffer =buffer;
    }
    public void run() {
        for (int i = 1; i <= 100; i++) {
            try {
                buffer.push(new Chicken(i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("produce a NO."+i+" chicken");
        }
    }

}

class Consumer extends Thread {
    Buffer buffer;
    public Consumer(Buffer buffer) {
        this.buffer =buffer;
    }

    public void run() {
        for (int i = 1; i <= 20; i++) {
            try {
                System.out.println("consume a NO."+buffer.pop().id+" chicken");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Chicken{
    int id;
    Chicken(int id) {
        this.id = id;
    }
}

class Buffer {
    Chicken[] chickens = new Chicken[10];
    int count = 0;
    public synchronized void push(Chicken chicken) throws InterruptedException {
        if (count == chickens.length) {
            this.wait();
        }
        chickens[count] = chicken;
        count++;
        this.notifyAll();
    }

    public synchronized Chicken pop() throws InterruptedException {
        if (count == 0) {
            this.wait();
        }

        count--;
        Chicken chicken = chickens[count];

        notifyAll();
        return chicken;
    }
}

输出结果:

produce a NO.1 chicken
produce a NO.2 chicken
produce a NO.3 chicken
produce a NO.4 chicken
produce a NO.5 chicken
produce a NO.6 chicken
produce a NO.7 chicken
produce a NO.8 chicken
produce a NO.9 chicken
produce a NO.10 chicken
produce a NO.11 chicken
consume a NO.10 chicken
consume a NO.11 chicken
produce a NO.12 chicken
consume a NO.12 chicken
produce a NO.13 chicken
consume a NO.13 chicken
consume a NO.14 chicken
consume a NO.9 chicken
produce a NO.14 chicken
consume a NO.8 chicken
consume a NO.15 chicken
produce a NO.15 chicken
produce a NO.16 chicken
consume a NO.7 chicken
produce a NO.17 chicken
consume a NO.17 chicken
consume a NO.18 chicken
produce a NO.18 chicken
consume a NO.16 chicken
produce a NO.19 chicken
produce a NO.20 chicken
consume a NO.19 chicken
consume a NO.20 chicken
consume a NO.6 chicken
consume a NO.5 chicken
consume a NO.4 chicken
consume a NO.3 chicken
consume a NO.2 chicken
consume a NO.1 chicken

上面的代码中,消费者线程的任务是需要消费20只鸡,生产者线程的任务是生产20只鸡,缓冲区能容纳10只已生产未消费的鸡。

生产的资源和消费的资源数要相等,否则导致其中一方线程结束,而另一方一直在缓冲区等待。

信号灯法

信号灯法使用标志变量来控制哪个线程需要等待,哪个线程需要唤醒。

以下代码演示如何使用信号灯法:

package com.cxf.multithread.produce_consume;

public class TestForFlag {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

class Player extends Thread {
    TV tv;
    public Player(TV tv) {
        this.tv = tv;
    }
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(i%2 == 0) {
                try {
                    this.tv.play("Spring night");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                try {
                    this.tv.play("Harry Porter");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv) {
        this.tv = tv;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                tv.watch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class TV{

    String content;
    boolean flag = true;

    public synchronized void play(String content) throws InterruptedException {

        if(!flag) {
            this.wait();
        }
        System.out.println("play a " + content);
        notifyAll();
        this.content = content;
        this.flag = !this.flag;
    }

    public synchronized void watch() throws InterruptedException {
        if (flag) {
            this.wait();
        }
        System.out.println("watch a " +content);
        notifyAll();
        this.flag = !this.flag;
    }
}

输出结果:

play a Spring night
watch a Spring night
play a Harry Porter
watch a Harry Porter
play a Spring night
watch a Spring night
play a Harry Porter
watch a Harry Porter
play a Spring night
watch a Spring night
play a Harry Porter
watch a Harry Porter
play a Spring night
watch a Spring night
play a Harry Porter
watch a Harry Porter
play a Spring night
watch a Spring night
play a Harry Porter
watch a Harry Porter

在生产者生产之后,和消费者消费之后才会分别改变标志位,让生产者和消费者的事件能够交替进行。

posted on 2021-10-25 10:53  菜小疯  阅读(189)  评论(0编辑  收藏  举报