线程--生产者消费者模式

来源:互联网 发布:visual studio php 编辑:程序博客网 时间:2024/05/18 00:05

如果对同一个对象多个线程进行操作容易造成死锁,为了解决这个问题我们用到了生产者消费者模式。

生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程--即所谓的“生产者”和“消费者”--在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键是保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆放弃数据),等到下次消费者消耗缓冲区中的数据时,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再次唤醒消费者。通常常用的方法有信号灯、管程等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。

下面通过示例来演示下:

Movie.java

/** * 一个场景,共同的资源 *生产者消费者模式信号灯法 *wait()等待,释放锁      sleep 不释放锁 *notify()/notifyAll():唤醒 */public class Movie {private String pic;//信号灯//flag-->T 生产者生产,消费者等待,生产完成后通知消费//flag-->F 消费者消费,生产者等待,消费完成后通知生产private Boolean flag=true;/** * 播放 * @param pic */public synchronized void play(String pic){if(!flag){//等待try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//开始生产try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("生产了:"+pic);//生产完毕this.pic=pic;//通知消费this.notify();//生产者停下this.flag=false;}public synchronized void watch(){if(flag){//消费者等待try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println("消费了:"+pic);//消费完毕//通知生产this.notifyAll();//消费停止this.flag=true;}}
Player.java

/** * 生成者 * */public class Player implements Runnable{private Movie m;public Player(Movie m) {super();this.m = m;}@Overridepublic void run() {for(int i=0;i<20;i++){if(0==i%2){m.play("大话西游");}else{m.play("功夫熊猫");}}}}

Watcher.java

public class Watcher implements Runnable{private Movie m;public Watcher(Movie m) {super();this.m = m;}@Overridepublic void run() {for(int i=0;i<20;i++){m.watch();}}}
Test.java

public class Test {public static void main(String[] args) {//共同的资源Movie m=new Movie();//多线程Player p=new Player(m);Watcher w=new Watcher(m);new Thread(p).start();new Thread(w).start();}}

执行结果:




原创粉丝点击