欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-05 09:04:47
...

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

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

本程序只有一个生产者和一个消费者,使用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();
			}
		}
	}
}