经典问题-生产者和消费者问题

生产者和消费者是一个多线程同步的经典案例,该问题描述了两个共享固定大小缓冲区的线程,即所谓的“生产者”和“消费者”,顾名思义,生产者指的就是生产一定的数据量到缓冲区,而消费者就是从缓冲区取走一定的数据。

生产者和消费者问题要解决一个死锁问题,就是当缓冲区已经满的时候,生产者占着它等待消费者来取走数据,而消费者则等着生产者让出缓冲区的权利好取走数据,于是就相互等待,从而造成死锁。

本程序只有一个生产者和一个消费者,使用wait和notify(nitify)方法来避免死锁问题,这里得提一下wait和notify(notifyAll)方法,线程中的wait、notify以及notifyAll方法:都是定义在Object类中的final方法,即所有的类都默认拥有这3个方法,但只用于synchronized关键字作用的范围内,并且是搭配着一起使用;wait方法是通知当前线程等待并释放对象锁;notify方法是通知等待此对象锁的一个线程重新获得线程锁;notifyAll是唤醒所有等待此对象锁的线程。

public class ProducerConsumer {
	
	public static void main(String[] args) {
		
		SyncStack myStack = new SyncStack(6);
		
		Producer producer = new Producer(myStack);
		Consumer consumer = new Consumer(myStack);
		
		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);
		
		t1.start();
		t2.start();
		
	}
}

class Bread {
	
	private int id;
	
	Bread(int id) {
		this.id = id;
	}
	
	public int getId() {
		return id;
	}
}


class SyncStack {
	
	private int size;
	private int index = 0;
	private Bread[] myBread;
	
	SyncStack(int size) {
		this.size = size;
		myBread = new Bread[size];
	}
	
	public synchronized void put(Bread bread) {
		while (index == size) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		myBread[index] = bread;
		++index;
		System.out.println("Producer puts bread: " + bread.getId());
		this.notify();
	}
	
	public synchronized Bread remove() {
		while (index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		--index;
		System.out.println("Consumer removers bread: " + myBread[index].getId());
		this.notify();
		return myBread[index];
	}	
	
}

class Producer extends Thread {
	
	private SyncStack myStack;
	
	Producer(SyncStack myStack) {
		this.myStack = myStack;
	}
	
	public void run() {
		
		for (int i = 1; i <= 20; ++i) {
			myStack.put(new Bread(i));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}


class Consumer extends Thread {
	
	private SyncStack myStack;
	
	Consumer(SyncStack myStack) {
		this.myStack = myStack;
	}
	
	public void run() {	
		for (int i = 1; i <= 20; ++i) {	
			Bread bread = myStack.remove();
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}


posted @ 2014-12-29 20:48  ihge2k  阅读(651)  评论(0编辑  收藏  举报