java多线程篇-生产者消费者问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lin1094201572/article/details/82388999

*前言

生产者消费者问题是java多线程中五个同步问题的经典模型之。

问题描述:

生产者生产产品,消费者消费产品,可以有一个或多个生产者生产产品供一个或多个消费者消费产品。

为使生产与消费并发,在生产者和消费者之间建立共享的缓冲区,生产者生产的产品放入缓冲区,消费者从缓冲区中消费产品。

生产者与消费者需保持同步,生产者不能在缓冲区已满时继续生产,消费者不能在缓冲区为空时消费产品。

解决方案:

1)缓冲区数据结构使用栈,生产者生产产品进栈,消费者消费产品出栈,该缓冲区栈作为多个线程共享资源。

2)多个生产和消费线程可以并发访问缓冲区,需要互斥锁来控制对缓冲区的操作。使用synchronized关键字修饰对缓冲区的操作方法,当执行被关键字修饰的方法的过程中会锁住当前缓冲区,即将缓冲区栈加上了互斥锁。

3)缓冲区栈中空时,消费线程进入阻塞状态,而生产线程需要为就绪状态,缓冲区栈中满时,生产线程进入阻塞状态,而消费线程需要为就绪状态。使用父类Object类的 wait() 方法,使拿住互斥锁的线程进入缓冲区栈对象中的 wait pool,同时确保其他所有生产线程就绪,使用 notifyAll() 方法叫醒其他所有线程。

代码实现:

产品类

class Item{
	int id;
	String name;
	Item(int id){
		this.id = id;
	}
	public String toString() {
		return "Item{id:"+id+"}";
	}
}

缓冲区栈类

class SynchronizedStack{
	// 记录存放数量
	int size = 0;
	// 初始化数组大小,即存储最大容量
	private Item[] items = new Item[6];
	
	// 进栈
	synchronized void push(Item item) {
		//若数组大小和存储数量相等,即存储已满
		while(items.length==size) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 叫醒其他所有线程等待拿锁,即叫醒该对象wait pool中所有线程
		this.notifyAll();
		items[size] = item;
		size++;
	}
	// 出栈
	synchronized Item pop() {
		while(size==0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 叫醒其他所有线程
		this.notifyAll();
		size--;
		return items[size];
	}
}

生产者类

class Producer implements Runnable{
	SynchronizedStack stack = null;
	Producer(SynchronizedStack stack){
		this.stack = stack;
	}
	@Override
	public void run() {
		for(int i=0; i<20; i++) {
			Item item = new Item(i);
			stack.push(item);
			System.out.println(Thread.currentThread().getName()+"-生产了-"+item);
			
			// 线程的sleep会一直贪婪的拿着锁,而wait会释放锁
			try {
				Thread.sleep((long) (Math.random()*500));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

消费者

class Consumer implements Runnable{
	SynchronizedStack stack = null;
	Consumer(SynchronizedStack stack){
		this.stack = stack;
	}
	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			Item item = stack.pop();
			System.out.println(Thread.currentThread().getName()+"-消费了-"+item);
			try {
				Thread.sleep((long) (Math.random()*500));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

问题模拟主线程类

public class ProducerConsumer {
	public static void main(String[] args) {
		// 缓冲区栈
		SynchronizedStack syncStack = new SynchronizedStack();
		// 生产者
		Producer producer = new Producer(syncStack);
		// 消费者
		Consumer consumer = new Consumer(syncStack);
		// 生产线程
		Thread producerThread = new Thread(producer,"producer");
		// 消费线程1
		Thread consumerThread1 = new Thread(consumer,"consumer1");
		// 消费线程2
		Thread consumerThread2 = new Thread(consumer,"consumer2");
		
		// 启动所有线程
		producerThread.start();
		consumerThread1.start();
		consumerThread2.start();
	}
}

这里简单模拟了一个生产者生产20个产品,两个消费者各消费10个产品。若生产者生产总数过少,所有消费线程会一直wait等待。若生产者生产过多,多于栈的存储空间,生产线程一直出去阻塞状态,少于则线程结束。

猜你喜欢

转载自blog.csdn.net/lin1094201572/article/details/82388999
今日推荐