0、概述
  多线程间通信,其实是多个线程操操作同一个资源,但是操作方式不同。典型实例有生产者和消费者,本文也通过实例来分析线程等待唤醒机制。
  1、相关API介绍
  public final void notify()
  唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会任意选择唤醒其中一个线程。
  public final void wait()
  当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。
  “为了实现监视器的排他性监视能力,JVM为每一个对象和类都关联一个;锁住了一个对象,是获得对象相关联的监视器”。
  wait(),notify(),notifyAll(),这些方法都使用在同步代码块中,因为要对持有监视器的线程进行操作,所以要使用在同步中,因为只有同步才有锁。值得说明的是:等待和唤醒必须是同一个锁(必须为同一个对象)。由于锁可以是任意对象,所以可以被任意对象调用的方法定义在object类中。
  2 、实例分析
  仓库类
  //等待和唤醒都是this锁
  public class Storage<T> {
  // 仓库大存储量
  private final int MAX_SIZE = 1000;
  private int storageSize = 100;
  private Object[] data;
  private int top = 0;
  public Storage(int size) {
  size = size <= 0 ? storageSize : size;
  size = size > this.MAX_SIZE ? this.MAX_SIZE : size;
  this.storageSize = size;
  data = new Object[this.storageSize];
  }
  public int getStorageSize() {
  return storageSize;
  }
  public synchronized T pop() {
  while (top == 0) {
  try {
  //等待
  wait();
  } catch (Exception ex) {
  ex.printStackTrace();
  }
  }
  top--;
  T t = (T) data[top];
  //唤醒所有线程
  notifyAll();
  return t;
  }
  public synchronized void push(T t) {
  while (top == storageSize) {
  try {
  wait();
  } catch (Exception ex) {
  ex.printStackTrace();
  }
  }
  data[top++] = t;
  notifyAll();
  }
  }
  生产者
  public class Producer implements Runnable {
  private Storage<String> storage;
  private volatile boolean breakLoop = false;
  public Producer(Storage<String> storage) {
  this.storage = storage;
  }
  @Override
  public void run() {
  int index = 1;
  while (true) {
  if (breakLoop) {
  break;
  }
  try {
  Thread.sleep(1000);
  } catch (Exception ex) {
  ex.printStackTrace();
  }
  storage.push("data:" + index);
  System.out.println("Producer data:" + index);
  index++;
  }
  }
  public void destroy() {
  this.breakLoop = true;
  }
  }
  消费者
  public class Consumer implements Runnable {
  private Storage<String> storage;
  private volatile boolean breakLoop = false;
  public Consumer(Storage<String> storage) {
  this.storage = storage;
  }
  @Override
  public void run() {
  while (true) {
  if (breakLoop) {
  break;
  }
  try {
  Thread.sleep(1000);
  } catch (Exception ex) {
  ex.printStackTrace();
  }
  System.out.println(Thread.currentThread().getName() + "Consumer:" + storage.pop());
  }
  }
  public void destroy() {
  this.breakLoop = true;
  }
  }