Java Thread wait()について、notify()の実用例【回転】

7317 ワード


//////////////////////////////////////////@author葉雨//////////これは重要なThreadの例です.注意が必要なのは、//wait()はsynchronized関数またはコードブロック内//wait()でsynchronized関数またはコードブロック制御権を取得したThreadを一時的に休ませ、制御権を喪失しなければならない//このとき、そのスレッドが制御権を喪失して待機に入るため、他のスレッドは制御権を取得し、適切な場合にnotifyAll()を呼び出すことができるwait()のスレッドを呼び覚ます.//起動されたスレッドは制御権を失っているため、起動されたスレッドが操作を終了するのを待つ必要があります.////だからwait()は確かにすぐに現在のスレッドに制御権を失わせ、他のスレッドは虚に乗じて入ることができます.//だからwait()の使用は、2つ以上のスレッドが存在し、異なる条件でwait()のスレッドを起動しなければならない.以下の例://ProductStackは生産者と消費者が共有する同期メカニズムであり、このメカニズムはどのような状況の生産者がwait()を必要とし、どのような状況の消費者がwait()/ProductStackを製品倉庫と見なすことができるかを決定する.製品倉庫がいっぱいになると、生産者スレッドはwait()を必要とし、製品倉庫の制御を放棄します.//このとき消費者スレッドが入って倉庫の制御権を得ることができます.消費者が製品を消費すると、倉庫は不満になります.//このとき消費者スレッドはnotifyAll()生産者スレッドになり、待機している生産者スレッドを呼び覚ます.//しかし、生産者が目覚めた後、すぐに生産することはできません.wait()の時に倉庫に対する制御権を失ったため、消費者スレッドが操作を終了するのを待つ必要があります.//だから特に注意しているのは、notifyAll()は現在のスレッドにすぐに制御権を譲るのではなく、他のwait()のスレッドを呼び覚ますだけで、//だから申し訳ありません.私はあなたを呼び覚ますにもかかわらず、倉庫を使い切ってから入らなければなりません.この点ははっきりしなければならない.//////逆に、倉庫が空いている場合、消費者スレッドはwait()になり、生産者スレッドが製品を生産するのを待っています.生産者プロセスは虚に乗じて入ってきて、生産者スレッドに製品//を生産させ、消費者スレッドを呼び覚ますようにします.この状況は上と似ています.//////////////////////////////////////////////////////////////////////////////////////////////////////////
package cn.com.dang;
 
public class ProducerConsumer {
      public static void main(String[] args) {
           ProductStack ps = new ProductStack();
           Producer p = new Producer(ps, "   1");
           Consumer c = new Consumer(ps, "   1");
           new Thread(p).start();
           new Thread(c).start();
      }
}
 
class Product {
      int id;
 
      private String producedBy = "N/A";
 
      private String consumedBy = "N/A";
 
      //     ,    ID       。
      Product(int id, String producedBy) {
           this.id = id;
           this.producedBy = producedBy;
      }
 
      //   ,         
      public void consume(String consumedBy) {
           this.consumedBy = consumedBy;
      }
 
      public String toString() {
           return "Product : " + id + ", produced by " + producedBy
                      + ", consumed by " + consumedBy;
      }
 
      public String getProducedBy() {
           return producedBy;
      }
 
      public void setProducedBy(String producedBy) {
           this.producedBy = producedBy;
      }
 
      public String getConsumedBy() {
           return consumedBy;
      }
 
      public void setConsumedBy(String consumedBy) {
           this.consumedBy = consumedBy;
      }
 
}
 
//   class    ,                    
class ProductStack {
      int index = 0;
 
      Product[] arrProduct = new Product[6];
 
      // push            
      public synchronized void push(Product product) {
           //       
           while (index == arrProduct.length) //        if(),    catch
                                            // exception    ,   index  
           {
                 try {
                      // here, "this" means the thread that is using "push"
                      // so in this case it's a producer thread instance.
                      // the BIG difference between sleep() and wait() is, once
                      // wait(),
                      // the thread won't have the lock anymore
                      // so when a producer wait() here, it will lost the lock of
                      // "push()"
                      // While sleep() is still keeping this lock
                      // Important: wait() and notify() should be in "synchronized"
                      // block
 
                      System.out.println(product.getProducedBy() + " is waiting.");
                      //   ,       push()
                      wait();
                 } catch (InterruptedException e) {
                      e.printStackTrace();
                 }
           }
           System.out.println(product.getProducedBy() + " sent a notifyAll().");
 
           //              wait(),           ,            ,     ,    
           notifyAll();
           //   ,notifyAll()  ,     ,          。
           arrProduct[index] = product;
           index++;
           System.out.println(product.getProducedBy() + "    : " + product);
      }
 
      // pop           
      public synchronized Product pop(String consumerName) {
           //       
           while (index == 0) {
                 try {
                      // here will be the consumer thread instance will be waiting ,
                      // because empty
                      System.out.println(consumerName + " is waiting.");
                      //   ,       pop()
                      wait();
                 } catch (InterruptedException e) {
                      e.printStackTrace();
                 }
           }
 
           System.out.println(consumerName + " sent a notifyAll().");
           //              wait(),           ,            ,     ,    
           notifyAll();
           //   ,notifyAll()  ,     ,          。
           //     
           index--;
           Product product = arrProduct[index];
           product.consume(consumerName);
           System.out.println(product.getConsumedBy() + "    : " + product);
           return product;
      }
}
 
class Producer implements Runnable {
      String name;
 
      ProductStack ps = null;
 
      Producer(ProductStack ps, String name) {
           this.ps = ps;
           this.name = name;
      }
 
      public void run() {
           for (int i = 0; i < 20; i++) {
                 Product product = new Product(i, name);
                 ps.push(product);
                 try {
                      Thread.sleep((int) (Math.random() * 200));
                 } catch (InterruptedException e) {
                      e.printStackTrace();
                 }
           }
      }
}
 
class Consumer implements Runnable {
      String name;
 
      ProductStack ps = null;
 
      Consumer(ProductStack ps, String name) {
           this.ps = ps;
           this.name = name;
      }
 
      public void run() {
           for (int i = 0; i < 20; i++) {
                 Product product = ps.pop(name);
                 try {
                      Thread.sleep((int) (Math.random() * 1000));
                 } catch (InterruptedException e) {
                      e.printStackTrace();
                 }
           }
      }
}