生产者消费者模式
生产者消费者模式
生产者消费者模式是线程协作的一种情况,意思是线程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
在生产者生产之后,和消费者消费之后才会分别改变标志位,让生产者和消费者的事件能够交替进行。