Javaマルチスレッドクラシック-プロデューサーおよびコンシューマー

1.通知待機

通知はスレッドのロックを解除し、待機はスレッドをロックします。

notifyメソッドとwaitメソッドを使用してスレッドを同期します。そうしないと、エラーが報告されます。

通知と待機は同期ロックに依存しているため、同期されたロックは通知と待機のスレッドで埋める必要があります。

次に、wait()とnotify()を使用して、プロデューサーとコンシューマーの間で並行性を実現する方法について説明し
 ます。1。明らかに、プロデューサーとコンシューマーが混沌とせずに同時に実行されるようにする必要があります。主な解決策は次のとおりです。プロデューサースレッドがいっぱいになると、wait()を呼び出してプロデューサーが本番を継続できないようにし、プロデューサーの完全なバッファーがコンシューマーによって消費されると、notify()を呼び出してプロデューサーをウェイクアップします。プロダクションを継続できることを彼に通知します。同じコンシューマーの場合、コンシューマースレッドのバッファーが空の場合、wait()を呼び出してコンシューマースレッドを停止し、コンシューマースレッドを停止して、プロデューサーが別のスレッドを生成するときに、notifyを呼び出す必要があります。 ()消費者を目覚めさせるスレッドは、彼が消費を続けることができることを彼に通知します。

ここで強調する必要があるのは、waitメソッドとnotifyメソッドはスレッドスレッドのメソッドではなく、オブジェクトのメソッドであるということです。

すべてのオブジェクトは同期オブジェクトとして使用できるため、正確には、待機と通知は同期オブジェクトのメソッドです。

wait()の意味
 1.この同期オブジェクトを占有しているスレッドに、現在の占有を一時的に解放して待機させます。したがって、waitを呼び出すための前提条件があり、同期ブロック内にある必要があります。そうでない場合、エラーが発生します。

notify()の意味
 1.この同期オブジェクトを待機しているスレッドに通知します。ウェイクアップして、現在のオブジェクトを再占有する機会があります。

  オブジェクトのnotify()メソッドを呼び出すと、このオブジェクトのモニター(ロック)を待機しているスレッドをウェイクアップできます。複数のスレッドがこのオブジェクトのモニターを待機している場合、1つのスレッドのみをウェイクアップできます。

  起動中のスレッドは、オブジェクトのモニターがすぐに取得されることを意味しません。notify()またはnotifyAll()を呼び出して同期ブロックを終了した後、オブジェクトロックを解放した後、残りのスレッドは実行用のロックを取得できます。

2.通知および待機プログラムのデモンストレーション

public class Test {
    
    
  // 在多线程间共享的对象上使用wait
  private static String shareObj = "true";

  public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    

    Thread1 a = new Thread1();
    a.setName("a");
    /* 启动线程a */
    a.start();

    Thread2 b = new Thread2();
    b.setName("b");
    /* 启动线程b */
    b.start();

  }

  static class Thread1 extends Thread {
    
    

    @Override
    public void run() {
    
    
      try {
    
    
        synchronized (shareObj) {
    
    
          System.out.println("开始等待线程获取锁");
          /* 等待获取锁,需要其他线程将对象锁进行释放 */
          shareObj.wait();
        }

      } catch (InterruptedException e) {
    
    
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      System.out.println(this.getName() + "线程,获取到锁");
    }
  }

  static class Thread2 extends Thread {
    
    
    @Override
    public void run() {
    
    
      try {
    
    
        synchronized (shareObj) {
    
    
          shareObj.notify();
          System.out.println("线程" + Thread.currentThread().getName() + "调用shareObj.notify()");

          /*
           * 只要当前线程等待2s后,线程Thread1才会被执行 因为只要执行完synchronized语句块,对象锁才会被释放
           * 当对象锁被释放的时候,线程Thread1才会执行,因为获得到锁
           */
          sleep(2000);
        }
      } catch (Exception e) {
    
    
        // TODO: handle exception
      }
      System.out.println(this.getName() + "释放了锁");
    }
  }
}

3.生産者と消費者の手順

package acc;

import java.util.Date;

public class Test {
    
    

  final static Account ac = new Account();

  /**
   * 多线程并发问题演示 当多个线程同时访问一个对象时就可能发生同步问题 如果想看bug,不要使用虚拟机,使用真实电脑测试
   * 
   * @param args
   */
  public static void main(String[] args) {
    
    

    ac.setN(1000);// 账户金额1000

    final Date dt = new Date();

    Thread xx = new Thread("张三") {
    
     // 连续存款50次,每次100
      @Override
      public void run() {
    
    

        try {
    
    

          for (int i = 1; i <= 50; i++) {
    
    
            System.out.println("");

            /**
             * 为代码段加锁,如果其他线程正在占用锁,这里就等待 此代码段开始之后就会占用这把锁,其他使用本锁的地方将会等待
             */
            synchronized (Test.class) {
    
    
              int n = ac.getN();// 获取余额
              System.out.println(this.getName() + " - 查询余额 :" + n);
              n = n + 100;

              sleep(1);
              ac.setN(n);
            }

            System.out.println(this.getName() + " - 存100查询 :" + ac.getN());
          }

        } catch (Exception e) {
    
    
          e.printStackTrace();
        }

        System.out.println(this.getName() + " -- OVER : " + ac.getN());
      }
    };

    xx.start();

    new Thread("李四") {
    
     // 连续存款50次,每次100
      @Override
      public void run() {
    
    

        try {
    
    

          for (int i = 1; i <= 50; i++) {
    
    
            System.out.println("");
            /**
             * 为代码段加锁,如果其他线程正在占用锁,这里就等待 此代码段开始之后就会占用这把锁,其他使用本锁的地方将会等待
             */
            synchronized (Test.class) {
    
    
              int n = ac.getN();// 获取余额
              System.out.println(this.getName() + " - 查询余额 :" + n);
              n = n - 100;

              sleep(1);
              ac.setN(n);

            }

            System.out.println(this.getName() + " - 取出100之后查询 :" + ac.getN());
          }

        } catch (Exception e) {
    
    
          e.printStackTrace();
        }

        System.out.println(this.getName() + " -- OVER : " + ac.getN());
      }
    }.start();

  }

}

おすすめ

転載: blog.csdn.net/weixin_43088443/article/details/112799813