线程同步中的“生产者和消费者”模式

原创 2016年06月01日 15:34:25

过多的线程同步可能会造成死锁

死锁通俗来讲就是两个或者两个以上线程,占用了对方下一步所需要的资源,多个线程僵持都无法结束任务的状态


生产者和消费者模式是一个多线程同步的经典案例

它利用信号灯来判断线程是否可以执行,可以避免线程的死锁问题

在java中,生产者与消费者模式是必须通过同步synchronized才可以实现的


下面的代码中有两种不近相同的该模式代码展示(Movie,Movie2),但是道理都是一样的


我们需要两个Runnable实现类用来创建线程Player,Watcher,一个Moive类作为共同竞争的资源,以及测试类App

其中这两个实现类都共同享有这个资源,那么就需要实现类做到以下两点

1.私有属性-资源类对象

2.带参构造方法-参数为资源类对象


/**
 * 生产者
 */
public class Player implements Runnable {
	private Movie2 m ;
	
	public Player(Movie2 m) {
		super();
		this.m = m;
	}

	@Override
	public void run() {
		for(int i=0;i<5;i++){
			m.play();
		}
	}
}



/**
 * 消费者
 */
public class Watcher implements Runnable {
	private Movie2 m ;
	
	public Watcher(Movie2 m) {
		super();
		this.m = m;
	}

	@Override
	public void run() {
		for(int i=0;i<5;i++){
			m.watch();
		}
	}
}



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


接下来就是核心代码,有几个要点需要注意

1.信号灯法的信号灯说白了也就是资源类的一个属性,它可以是布尔类型也可以是int类型

2.这里用到了Object类的两个方法  wait(),notify()/notifyAll()





/**
 * 资源类
 */
public class Movie {
	private String pic = "Candy";

	// flag -->T 生产生产,消费者等待 ,生产完成后通知消费
	// flag -->F 消费者消费 生产者等待, 消费完成后通知生产
	private boolean flag = true;

	/**
	 * 生产者生产,this指Player对象
	 * 
	 * @throws InterruptedException
	 */
	public synchronized void play() {
		if (!flag) {

			// 生产者等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		// 生产者---生产
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("生产了:" + pic);
		this.pic = pic;

		// 通知消费
		this.notify();

		// 生产者停下
		this.flag = false;
	}

	/**
	 * 消费者,this指Watcher对象
	 * 
	 * @throws InterruptedException
	 */
	public synchronized void watch() {
		if (flag) {

			// 消费者等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		// 消费者---开始消费
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("消费了" + pic);

		// 通知生产者
		this.notifyAll();

		// 消费停止
		this.flag = true;
	}
}





之前的资源类中作为信号灯的是一个布尔变量,从输出结果中也可以看出用布尔变量做为信号灯有一个缺点

那就是生产者和消费者是同步的,生产一个消费一个,这与现实生活太不吻合了

所以在Movie2类中,加入了List<Goods>,那么此时信号灯就是list的实际长度了

public class Goods {
	public String name;
	public Goods(String name){
		this.name=name;
	}
}


/**
 * 资源类二
 */
import java.util.ArrayList;
import java.util.List;

public class Movie2 {

	private int flag = 0;
	private int maxListSize = 10;
	private List<Goods> goodsList;

	public Movie2() {
		goodsList = new ArrayList<Goods>();
	}

	// 只要没有超过最大限制,生产者一直生产
	public synchronized void play() {
		if (maxListSize <= goodsList.size()) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//将生产的物质添加到list中
		Goods g = new Goods("candy");
		goodsList.add(g);
		System.out.println("creat--->" + (++flag) + g.name);

		//唤醒消费者
		this.notify();

	}

	public synchronized void watch() {

		//只要有物资,消费者就可以消费
		if (goodsList.size() <= 0) {
			try {

				this.wait();

			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println("use---" + (flag--)+ goodsList.get(goodsList.size() - 1).name);
		
		//从list中删除被消费的物资
		goodsList.remove(goodsList.size() - 1);

		//唤醒生产者
		this.notify();
	}
}


输出结果每次运行都不尽相同


版权声明:本文为博主原创文章,未经博主允许不得转载。

java线程 (一)生产者消费者模式-线程同步问题

转载请标明出处: http://blog.csdn.net/xiaohai0504/article/details/7003975  引言   生产者和消费者问题是线程模型中的经...

Qt之线程同步(生产者消费者模式 - QWaitCondition)

简述生产者将数据写入缓冲区,直到它到达缓冲区的末尾,这时它从开始位置重新启动,覆盖现有数据。消费者线程读取数据并将其写入标准错误。Wait conditions(等待条件)使得比单独使用 mutexe...

Java线程同步与死锁、生产者消费者模式以及任务调度等

Thread类基本信息方法 线程同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个...

线程同步–生产者与消费者模式

线程同步–生产者与消费者模式 多线程GooglethreadJVMSecurity 生产者与消费者模式简单介绍:生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区...

JAVA线程同步——消费者和生产者模式

场景介绍 我们有一个数据缓冲区,一个或者多个生产者把数据存入这个缓冲区,一个或者多个消费者从缓冲区中取出数据 缓冲区中的是共享数据 当缓冲区满的时候不能生产者将不能再放入数据到缓冲区(生产者线程阻塞)...

java线程(三) 生产者消费者模式-线程同步问题

引言   生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生...

Qt之线程同步(生产者消费者模式 - QSemaphore)

简述生产者将数据写入缓冲区,直到它到达缓冲区的末尾,这时,它从开始位置重新启动,覆盖现有数据。消费者线程读取数据并将其写入标准错误。Semaphores 使得比 mutexes 有一个更高级的并发性成...

线程同步--生产者消费者问题

  • 2009年07月05日 22:15
  • 5KB
  • 下载

Qt线程同步之一个生产者多个消费者

QMutex QMutex类提供的是线程之间的访问顺序化。 QMutex的目的是保护一段代码,使得同一时间只有一个线程可以访问它。但在一个线程中调用lock(),其它线程将会在同一地点试图调用lo...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线程同步中的“生产者和消费者”模式
举报原因:
原因补充:

(最多只允许输入30个字)