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个以内。 这个问题,只需要把消费者的睡眠时间加长一些即可,也或者可以多增加一些消费者,更贴近实际。