Javaのマルチスレッドベース(B)

簡単な紹介

パートではJavaのマルチスレッドの基礎()我々は、我々は特定のメソッドを見て、方法職場での活用に私たちを許可するこの区別を一般的な方法のいくつかのスレッドを述べました。

メソッドのメソッドを待って通知

ではObject、クラスの定義wait方法およびnotify方法、waitアクションのメソッドが待機状態に現在のスレッドは、現在のスレッドが置かれるようにすることです预执行队列、ますwaitの呼び出し、コードはそれが通知または中断されるまで実行方法で停止wait方法の前に、スレッドが取得する必要がありますオブジェクトをロックし、それだけであることができる同步方法か、同步代码块呼び出しwait方法、および方法は、現在のスレッドのロックが保持しているロックを解除します。notifyウェイクアップ方法は、現在のオブジェクト上で待機することで单个线程、スレッドスケジューラが選択されます、待機中の複数のスレッドがある場合は、wait彼らの問題をスレッドがnotifyそれを受信した場合でも、手段対象オブジェクトのロックを取得するために、そして待ちます予告、スレッドはすぐに待つ必要があり、オブジェクトのロックを取得しないnotifyロックはそれを解放することをスレッド。そして、waitといった方法notify方法が唯一にすることができ同步方法たり同步代码块、コール。また、同様のアプローチがありnotifyAll、その役割は、現在のオブジェクトを待機して目を覚ますことです、所有线程

プロデューサー次の消費者は、例示しwaitた方法およびnotify使用方法を:

/**
 * @author mghio
 * @date: 2019-12-14
 * @version: 1.0
 * @description: 线程 wait() 和 notify() 方法使用示例
 * @since JDK 1.8
 */
public class ThreadWaitAndNotifyDemo {

  public static void main(String[] args) {
    Producer producer = new Producer();
    producer.start();
    new Consumer("Consumer One", producer).start();
    new Consumer("Consumer Two", producer).start();
    new Consumer("Consumer Three", producer).start();
    new Consumer("Consumer Four", producer).start();
  }

  static class Producer extends Thread {

    List<String> messageList = new ArrayList<>(2);

    @Override
    public void run() {
      try {
        while (true) {
          Thread.sleep(2000);
          synchronized (messageList) {
            String message = String.format("producer message [create time:%s]", LocalDateTime.now());
            messageList.add(message);
            System.out.println("Producer " + getName() + " producer a msg: " + message);
            messageList.notify();
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    String getMessage() {
      synchronized (messageList) {
        if (messageList.size() == 0) {
          try {
            messageList.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        return messageList.remove(0);
      }
    }
  }

  static class Consumer extends Thread {

    private Producer producer;

    public Consumer(String name, Producer producer) {
      super(name);
      this.producer = producer;
    }

    @Override
    public void run() {
      while (true) {
        String message = producer.getMessage();
        System.out.println("Consumer " + getName() + " get a msg: " + message);
      }
    }
  }
}
复制代码

出力:

Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:42.319]
Consumer Consumer One get a msg: producer message [create time:2019-12-14T22:45:42.319]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:44.324]
Consumer Consumer Two get a msg: producer message [create time:2019-12-14T22:45:44.324]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:46.325]
Consumer Consumer Three get a msg: producer message [create time:2019-12-14T22:45:46.325]
Producer Thread-0 producer a msg: producer message [create time:2019-12-14T22:45:48.328]
Consumer Consumer Four get a msg: producer message [create time:2019-12-14T22:45:48.328]
复制代码

プロデューサーの循環消費者のスレッドの呼び出しgetMessageメッセージのリストがあれば、メッセージを取得する方法を、messageList空で、メッセージリストの呼び出しwait待機状態にスレッドを取得する方法を、メッセージが2秒ごとに生成され、メッセージリストの生産に置かれているmessageList。への呼び出しが成功した後、notifyこの方法は、ウェイクアップであるwaitコールで、留意すべきメッセージ、消費するスレッドの状態waitnotify上記の例の方法は、されたときに最初のオブジェクトのロックを獲得しなければならないsynchronizedコードブロックと呼ばれるが。

睡眠方法

そしてwaitnotify異なる方法、sleepで定義されたメソッドThreadメソッド名からクラスは、このメソッドの役割は作ることであることを認識することができ当前线程休眠、すなわち、メソッドの後から現在のスレッドと呼ばれる运行状态(Running)状态に入る阻塞(休眠)状态(Blocked)と、睡眠に時間を与えなければならない、スリープ現在のスレッドこの時間は、指定されたスリープ時間以上になります。スレッドが再び目を覚ますと、スレッド阻塞状态(Blocked)にターンを就绪状态(Runnable)して、CPUの実行スケジュールを待ちます。sleep次のようにメソッドのサンプルコードは、次のとおりです。

/**
 * @author mghio
 * @date: 2019-12-14
 * @version: 1.0
 * @description: 线程 sleep() 方法使用示例
 * @since JDK 1.8
 */
public class ThreadSleepDemo {

  private static Object object = new Object();

  public static void main(String[] args) {
    MyThread myThreadOne = new MyThread("t1");
    MyThread myThreadTwo = new MyThread("t2");
    myThreadOne.start();
    myThreadTwo.start();
  }

  static class MyThread extends Thread {

    public MyThread(String name) {
      super(name);
    }

    @Override
    public void run() {
      synchronized (object) {
        try {
          for (int i = 0; i < 5; i++) {
            System.out.println(String.format("%s: %d", this.getName(), i));
            if (i % 2 == 0) {
              Thread.sleep(2000);
            }
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
}
复制代码

出力:

t1: 0
t1: 1
t1: 2
t1: 3
t1: 4
t2: 0
t2: 1
t2: 2
t2: 3
t2: 4
复制代码

我々は2つのスレッドを開始したt1t2の二つのスレッドrunの方法が同じオブジェクトを参照するobject(同期ロックsynchronized (object))、最初のスレッドでけれどもt1ときi2回のコールで割り切れるThread.sleep(2000)スレッドをスリープ2 sまで現在のスレッドを作ることが、今回t2もので、あなたは、実行するためのCPUを実行するための権利を取得することはできませんt1呼び出すスレッドsleep方法が解放されませんobject開催された同期ロックを。私たちがコメントした場合はsynchronized (object)、再びプログラムの実施後に、糸t1t2交互として以下のコメントの後に出力され、実行することができます。

t2: 0
t1: 0
t1: 1
t2: 1
t1: 2
t2: 2
t2: 3
t1: 3
t2: 4
t1: 4
复制代码

利回り法

yieldで定義されたメソッドThreadのクラスは、スレッドの具体的な方法です。このアプローチの主な効果は让步、現在のスレッドからそれを作ることに运行状态(Running)なり、就绪状态(Runnable)他の人が同じ優先度を持つように、就绪状态CPU(への権利を得るために、実行のスレッドPS: CPU 会从众多的处于就绪状态的线程里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到)、しかし、それは現在のスレッドの呼び出しを保証するものではありませんyield、他の後に持っていました同じ優先度のスレッドが実装権を取得することができます、現在のスレッドの中に存在し入力することができます运行状态(Running)実行し続けます。yield次のようにメソッドのサンプルコードは、次のとおりです。

/**
 * @author maguihai
 * @date: 2019-12-14
 * @version: 1.0
 * @description: 线程 yield() 方法使用示例
 * @since JDK 1.8
 */
public class ThreadYieldDemo {

  public static void main(String[] args) {
    MyThread myThreadOne = new MyThread("t1");
    MyThread myThreadTwo = new MyThread("t2");
    myThreadOne.start();
    myThreadTwo.start();
  }

  static class MyThread extends Thread {

    MyThread(String name) {
      super(name);
    }

    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        System.out.println(String.format("%s [%d] ---> %d", this.getName(), this.getPriority(), i));
        if (i % 2 == 0) {
          yield();
        }
      }
    }
  }
}
复制代码

出力:

t1 [5] ---> 0
t2 [5] ---> 0
t1 [5] ---> 1
t1 [5] ---> 2
t1 [5] ---> 3
t1 [5] ---> 4
t1 [5] ---> 5
t1 [5] ---> 6
t1 [5] ---> 7
t1 [5] ---> 8
t1 [5] ---> 9
t2 [5] ---> 1
t2 [5] ---> 2
t2 [5] ---> 3
t2 [5] ---> 4
t2 [5] ---> 5
t2 [5] ---> 6
t2 [5] ---> 7
t2 [5] ---> 8
t2 [5] ---> 9
复制代码

上記の出力からわかるように、スレッドt1の変数がi2で割り切れること、およびスレッドに切り替わりませんでしたt2実行する、それはまた、私たちは、上記の、言っ確認yieldあなたがスレッドを作ることができるが、この方法が运行状态なり就绪状态、それはない、しかし、それが正しいCPUにそれによって取得した他のスレッドの実行を行います运行状态、さらに、現在のスレッドと同じ優先度の他、もしyield真上ロック(この例の証拠を解放しない方法でrun追加する方法synchronized (obj)に、この時間t2スレッドスレッドがするまで、私たちは待っていますt1、実装後に実行されます)。

メソッドに参加

いくつかのシーンでは、我々はサブスレッド時間のかかる作業の一部で実行する必要があるが、我々はそう、あなたが使用することができ、仕上がり後のエンドまで、メインスレッドと子スレッドの実行を待機しなければならないjoin方法を、および方法は、で定義されThreadたクラス、メソッド役割は次のとおりです。让主线程等待子线程执行结束之后才能继续执行例では、見てみましょう:

/**
 * @author maguihai
 * @date: 2019-12-15
 * @version: 1.0
 * @description: 线程 join() 方法使用示例
 * @since JDK 1.8
 */
public class ThreadJoinDemo {

  public static void main(String[] args) {
    try {
      MyThread myThread = new MyThread("t1");
      myThread.start();
      myThread.join();
      System.out.println(String.format("%s ---> %s finish", LocalDateTime.now(), Thread.currentThread().getName()));
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  static class MyThread extends Thread {

    MyThread(String name) {
      super(name);
    }

    @Override
    public void run() {
      System.out.println(String.format("%s ---> %s start", LocalDateTime.now(), this.getName()));
      // 模拟耗时操作
      try {
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(String.format("%s ---> %s finish", LocalDateTime.now(), this.getName()));
    }
  }
}
复制代码

出力:

2019-12-15T00:22:55.971 ---> t1 start
2019-12-15T00:22:57.984 ---> t1 finish
2019-12-15T00:22:57.985 ---> main finish
复制代码

メインスレッドでmain通じnew MyThread("t1")新しいスレッドt1次に、t1.start()スレッドを開始しt1、実行t1.join()しますメインスレッドを入力した後に阻塞状态待つt1実行の終了を。子供が糸t1の端を、それは、CPUを実行するための権利を再取得するためにメインスレッドをメインスレッドを覚ますだろう、メインスレッドがダウンして実行し続けます。使用してjoin、メインスレッドの終了後に次のような方法は終了する子スレッドを待ちます。

概要

これらは、導入されたいくつかの一般的なスレッド方法や具体的な知識の概要を使用しています。

おすすめ

転載: juejin.im/post/5df5f75a5188251251353224