IT干货网

生产者消费者模式

qq123 2022年03月12日 编程设计 144 0

生产者消费者模式

生产者消费者模式是线程协作的一种情况,意思是线程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 

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


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

java线程同步处理并发问题