生产者与消费者问题是多线程同步的一个经典问题。生产者和消费者同时使用一块缓冲区,生产者生产商品放入缓冲区,消费者从缓冲区中取出商品。我们需要保证的是,当缓冲区满时,生产者不可生产商品;当缓冲区为空时,消费者不可取出商品。
wait()与notify()方法
Lock与Condition机制
BlockingQueue阻塞队列
wait()方法使用条件: wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
当生产产品数量满时,调用wait()方法,使得生产者释放锁,当前线程阻塞,消费者线程可以获得锁。当产品数量为空时,调用wait()方法,使得消费者释放锁,当前线程阻塞,生产者线程可以获得锁。notify()方法使用条件: notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
如果刚执行的是消费者,那么产品数量为0,就执行wait()方法等待。那么在执行生产者时,只要生产一个产品就会通过notify()方法唤醒消费者,让消费者来消费产品。如果生产者生产产品过快,消费者来不及消费,并且到达产品上限。那么生产者就执行wait()方法等待。在消费者消费一个产品就会通过notify()方法唤醒生产者,让生产者生产产品。代码如下:
//调度类 public class Clerk { //共享资源 产品数量 private static int productCount = 0; //生产产品 //必须加上同步方法,不然两个线程会产生线程安全问题 public synchronized void produceProduct(){ if (productCount < 20){ productCount++; System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品"); //唤醒等待的消费者 notify(); }else { //等待 try { //产品数量满了,进入等待 wait(); System.out.println("生产满了奥,我要休息一下"); } catch (InterruptedException e) { e.printStackTrace(); } } } //消费产品 public synchronized void consumeProduct(){ if (productCount > 0){ System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品"); productCount--; //唤醒等待的生产者 notify(); }else { try { //产品数量为空,进入等待 wait(); System.out.println("商品没了奥,我要休息一下"); } catch (InterruptedException e) { e.printStackTrace(); } } } } //生产者 public class Producer extends Thread { private Clerk clerk; public Producer(Clerk clerk){ this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":开始生产产品....."); while (true){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } //消费者 public class Consumer extends Thread { private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":开始消费产品....."); while (true){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); } } } //测试类 模拟两个生产者,两个消费者 public class Test { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); p1.setName("生产者1"); Producer p2 = new Producer(clerk); p2.setName("生产者2"); Consumer c1 = new Consumer(clerk); c1.setName("消费者1"); Consumer c2 = new Consumer(clerk); c2.setName("消费者2"); p1.start(); p2.start(); c1.start(); c2.start(); } }运行结果如下: