java多线程通信的经典例题:生产者消费者问题

java多线程有很多经典例题,比如窗口售票问题,生产消费问题。今天就在这里详细讲一下生产者消费者问题:

问题描述: 生产者(producer)将商品交给店员(Clerk),而消费者(Customer)从店员处取走商品,店员的货架上只能放一定数量的商品,如果生产者试图生产更多的商品,店员会叫生产者停一下,如果货架上有空位放商品再通知消费者继续生产。如果没有商品了,会告诉消费者等一下,如果店中有商品了再通知消费者来取走商品。

看到这个问题,我们不要去急着写代码,先来分析一下该题中会出现的多线程的知识点: 1.是否要用到多线程? 这是肯定的,消费和生产的动作可以同时进行,所以会有一个生产者线程,消费者线程。 2.是否要共享数据?是否涉及到了线程安全问题? 是,商品是生产者和消费者共享的数据。涉及到了线程安全问题,需要用同步机制(三种)来解决。 3.是否涉及到线程通信? 是,货架空是需要通知生产者生产商品,货架有商品时通知消费者来取走商品。

分析过了之后,我们就可以着手写代码了 本题中可划分3个类,即商品类(Clerk),生产者(Producer),消费者(Customer)

商品类:需要统计和显示商品的数量,有生产商品的方法,消费商品的方法 生产者:提供线程,当货架未满时不断循环提供商品。 消费者:提供线程,当货架有商品时不断循环消费商品。

代码如下:

public class Test {
          
   
	public static void main(String[] args) {
          
   
		Clerk clerk=new Clerk();
		Producer p1=new Producer(clerk);
		p1.setName("生产者1");
		
		Customer c1=new Customer(clerk);
		c1.setName("消费者1");
		
		p1.start();
		c1.start();
	}
}
/*
 * 商品类
 */
class Clerk{
          
   
	private int ProductCount=0;

	//生产商品
	public synchronized void ProduceProduct() {
          
   
		// TODO Auto-generated method stub
		if(ProductCount<20) {
          
   
			ProductCount++;
			System.out.println(Thread.currentThread().getName()+"正在生产第"+ProductCount+"个商品");
			notify();
		}else {
          
   
			//等待
			try {
          
   
				wait();
			} catch (InterruptedException e) {
          
   
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}

	//消费商品
	public synchronized void CustomeProduct() {
          
   
		// TODO Auto-generated method stub
		if(ProductCount>0) {
          
   
			System.out.println(Thread.currentThread().getName()+"正在消费第"+ProductCount+"个商品");
			ProductCount--;
			
			notify();
		}else {
          
   
			//等待
			try {
          
   
				wait();
			} catch (InterruptedException e) {
          
   
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
/*
 * 生产者
 */
class Producer extends Thread{
          
   

	private Clerk clerk;
	
	public Producer(Clerk clerk) {
          
   
		super();
		this.clerk = clerk;
	}

	@Override
	public void run() {
          
   
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"开始生产商品...");
		
		while(true) {
          
   
			
			try {
          
   
				Thread.sleep(100);
			} catch (InterruptedException e) {
          
   
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			clerk.ProduceProduct();
		}
	}
}
/*
 * 消费者
 */ 
class Customer extends Thread{
          
   
	private Clerk clerk;

	public Customer(Clerk clerk) {
          
   
		super();
		this.clerk = clerk;
	}

	@Override
	public void run() {
          
   
		// TODO Auto-generated method stub
		
		System.out.println(Thread.currentThread().getName()+"开始消费商品...");
		
		while(true) {
          
   
			
			try {
          
   
				sleep(100);
			} catch (InterruptedException e) {
          
   
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			clerk.CustomeProduct();
		}
	}
}

此时运行后你会发现生产者每生产一个商品很快就会被消费者拿走,货架商的数量一直保持在2个以内。 这个问题,只需要把消费者的睡眠时间加长一些即可,也或者可以多增加一些消费者,更贴近实际。

经验分享 程序员 微信小程序 职场和发展