Javaマルチスレッドプログラミングコアテクノロジー-生産者消費者モデル

2840 ワード

生産者消費者モデルは同時の古典的な問題であり、具体的なシーンはバッファが倉庫としてあり、生産者は製品を追加することができ、消費者はそこから製品を取り出すことができる.生産者の消費者問題を解決するには,wait()/notify方式とBlockingQueue方式の2つの方式を採用することができ,ここでは主に第1の方法について議論し,第2の方法についてはRangerのAuditモデルを参照することができる.
wait()/notify()はObjectの2つの方法であり、同時実行中によく見られる2つの方法でもあります.waitは、notifyが実行を続行することを通知するまでスレッドをブロックします.この2つの方法をコードで説明します.
public class MyThread implements Runnable {
  private String name;
  private List list = new ArrayList();
  private final int size = 10;

  public void produce(int num) throws Exception {
    while (true) {
      synchronized (list) {
        while (list.size() + num > size) {
          System.out.println(Thread.currentThread().getName()+" , ");
          list.wait();
        }
        System.out.println(Thread.currentThread().getName()+" ");
        for (int i = 0; i < num; i++) {
          list.add("hello, world");
        }
        list.notify();
      }
      Thread.sleep(1000);
    }
  }
  public void consume() throws Exception {
    while (true) {
      synchronized (list) {
        while (list.size() == 0) {
          System.out.println(Thread.currentThread().getName()+" , ");
          list.wait();
        }
        System.out.println(Thread.currentThread().getName()+" ");
        list.remove(0);
        list.notify();
      }
      Thread.sleep(1000);
    }
  }
  public void setName(String name) {
    this.name = name;
  }

  public void run() {
    try {
      if ("producer".equals(name)) {
        produce(1);
      }
      else {
        consume();
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    try {
      MyThread myThread = new MyThread();
      myThread.setName("producer");
      Thread t1 = new Thread(myThread);
      Thread t4 = new Thread(myThread);
      t1.start();
      t4.start();
      Thread.sleep(1);
      myThread.setName("consumer");
      Thread t2 = new Thread(myThread);
      Thread t3 = new Thread(myThread);
      t2.start();
      t3.start();
    }
    catch (Exception e) {

    }
  }
}

MyThreadはlistを製品倉庫として提供し,produceとconsume法は製品と消費製品の生産過程をシミュレートした.注目すべきは、listは複数のスレッドにわたって動作するため、生産でも消費でもlistにロックをかけ、「汚れた読み取り」が発生しないようにする必要があるからです.リストに製品が過剰である場合、消費者が一定の製品を消費するまで、生産者のproduceプロセスを一時停止する必要があり、倉庫が新製品を収容し、生産者に通知を送信して生産を継続することができるようにする.同様に、倉庫が空いている場合、生産者が製品を生産した後、消費者に通知を送るまで、消費者のconsumeプロセスを一時停止する必要があります.ここでの一時停止/通知はwait()/notify()メソッドによって実現される.
wait()とnotify()は同期ブロックで使用する必要があります.wait()はスレッドを待機させ、notify()はスレッドの継続を通知します.wait状態にあるスレッドが複数ある場合、1つのnotifyはランダムに1つのスレッドの継続を通知し、他のスレッドはwait状態にあることに注意してください.一方、notifyAll()メソッドはwait状態にあるすべてのスレッドに実行を継続するように通知しますが、waitが同期コードブロックにあるため、通知を受けるとスレッドがwait状態を終了するだけで、本当に実行を継続できるかどうかはスレッドが同期ロックを奪うかどうかにかかっています.