(一)生产者消费者模式原理:

在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。生产消费者模式如下图:

(二)代码实现

生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好。最关键就是内存缓冲区为空的时候消费者必须等待,而内存缓冲区满的时候,生产者必须等待。其他时候可以是个动态平衡:   首先设置Market类: 其中变量有:Max(仓库最大值),List(用于存放数据) 方法有Producer(生产方法),Cost(消费方法)

public class Market{

private int Max=20;

private Listlist=new ArrayList();

public synchronized void producer()throws InterruptedException{ //设置锁

if(list.size()>=20){

this.wait(): //超过容量时,等待

}

System.out.println("***开始生产,现在数量为"+list.size());

list.add("a");

System.out.println("***生产后数量为"+list.size());

this.notify(); //唤醒线程

}

public synchronized void cost()throws InterruptedException{

if(list.size()<0){

this.wait(); //线程休眠

}

System.out.println("开始消费,现在数量为:"+list.size());

list.remove(0);

System.out.println("消费后数量为:"+list.size());

this.notify(); //唤醒线程

}

}

其次分别时Producer和Cost类,都要继承Thread类,重写run方法

public class Producer extends Thread{ //继承run方法

private Market market;

public Producer(Market market){

this.market=market;

}

public void run(){

while(true) {

try {

Thread.sleep(new Random().nextInt(500)); //设置时间延迟

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

market.production(); //调用生产方法

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

public class Cost extends Thread{ //继承run方法

private Market market;

public Cost(Market market){

this.market=market;

}

public void run(){

while(true) {

try {

Thread.sleep(new Random().nextInt(500)); //设置时间延迟

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

market.cost(); //调用消费方法

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

最后写出测试类,启动线程

public class Test{

public static void main(String[]args){

Market market=new Market();

Producer p1=new Producer(market);

Producer p2=new Producer(market);

Producer p3=new Producer(market);

Cost c1=new Cost(market);

Cost c2=new Cost(market);

p1.start(); //启动线程

p2.start();

p3.start();

c1.start();

c2.start();

}

}

得到的运行结果为: 可知模拟的生产者消费者模式

(三)代码关键点分析:

1.锁问题:

对于Market中的Producer方法和Cost方法,要使用Synchronized关键字同步非静态方法,且要与wait()方法放在一起,使得在多个消费者生产者线程访问Market中的共享资源时不会发生线程安全问题,并且可以保证锁的时同一个对象

public synchronized void producer()

public synchronized void cost ()

2.线程的等待与重启

在生产时达到仓库的最大值后,要停止生产,即让生产的线程处于等待状态,此时需要调用wait()方法,

if(list.size()>=20){

this.wait(); //线程休眠

}

this.notify(); //唤醒线程

要用this来调用wait()方法,而不能用list,是因为被加锁的对象this在调用wait()和notify(),加锁的对象调用 wait() 方法后,线程进入等待状态,直到在加锁的对象上调用 notify() 方法来唤醒之前进入等待的线程

3.While循环放置在Producer和Cost类的run方法中:

使用while循环是原因:要保证线程可以一直运行下去:

public void run(){

while(true) {

try {

Thread.sleep(new Random().nextInt(500)); //设置时间延迟

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

market.cost(); //调用消费方法

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

如果把while循环放在Market中,则睡眠的线程被唤醒之后有可能不满足while()中的条件判定,使得线程线程无法再调用Market中的producer方法,从而无法唤醒线程,因此要放在线程外

4.时间延迟问题:

若要模拟生产和消费的随机过程,还要设置时间延迟

public void run(){

while(true) {

try {

Thread.sleep(new Random().nextInt(500)); //设置时间延迟

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

market.cost(); //调用消费方法

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

放在Producer类中的原因是只有放在run方法中,线程运行时才会具有随机性 否则会发生只有生产达到最大值后才会开始消费

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: