Javaのマルチスレッドの基礎()

簡単な紹介

前記接触で多线程私たちのプログラムにおける前は、いつでもコールを1つのステップを実行することができます单线程すべての手順を実行する必要がありますあなたの前に開発されたシングルスレッドプログラムのパスで順次実行され、後者は実行されます。単一スレッドも明らかで、より安定した相対的な利点は、マルチスレッド、よりスケーラブルなアプリケーションの開発は比較的容易です。しかし、それぞれが新しいタスクを開始する権限を待たなければならないため、マルチスレッドよりも低い効率で得られ、完了し、時にはアプリケーションは仮死の現象が現れます。完全に機能するマルチプロセッサの賛成でマルチスレッドを使用します。マルチスレッド・プロセスを作成することにより、各スレッドは、各プロセッサが完全に動作しているように、同時アプリケーションを可能にする、プロセッサ上で実行されています。マルチスレッドは、Javaを学習の非常に重要な側面である、Javaは各プログラマは基本的なスキルを習得しなければならないということです。この記事では、Javaマルチスレッドまとめのいくつかの基本的な知識についてです。

プロセスとスレッドの違い

プロセス

プロセスは操作系统资源分配、それが基礎となるオペレーティング・システムである、基本ユニット生じる活性である場合、プロセッサ上のプログラムおよびデータの実行順序。実行するためのメモリへのプログラムは、それがプロセスになります。プロセスは、プログラムを実行するプロセスであり、特定の別個の機能を有します。本質的には、動的に生成されたプロセスのオペレーティングシステムでのプログラムの実行、動的な破壊の過程は、独自のライフサイクルと異なる動作状態の様々なています。一方、プロセスはまた、並行性を有し、それは(フォワード、独立によれば、他の処理と並行して一緒に予測不可能な速度を実行することができますPS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

スレッド

スレッドがある任务调度和执行とも呼ばれる基本単位、轻量级进程スレッドIDによってスレッド、現在の命令ポインタ(PC)、セットスタックコンポーネントを登録します。スレッドがシステムリソースを所有していない、それだけで、実行時にはほとんど不可欠なリソースを持っていますが、それは同じプロセスに属するプロセスとスレッドが所有しているすべてのリソースを共有することができます。スレッドは、唯一のプロセスに属することができ、プロセスは複数のスレッドを持つことができますが、少なくとも一つのスレッドがあります。

両者の違い
  1. スケジュール独自のリソースの基本単位としての基本的な単位プロセスとしてスレッドのスケジューリングおよび割り当てを
  2. 並行処理プロセスの間に同時に実行することができるだけでなく、同じプロセスの複数のスレッド間で同時に実行することができます
  3. 資源の持つプロセスがリソースを持つ独立したユニットで、スレッドはシステムリソースを持っていませんが、リソースへのアクセスのプロセスの一部であります
  4. オーバーヘッドの作成または取り消しのプロセスを、システムが再計算されなければならないためと資源回収時に、システムのオーバーヘッドにつながる作成のコストやREVOKEスレッドよりも有意に大きいです

スレッドの道を作成します。

Javaのスレッドクラスのスレッドを表し、すべてのスレッドオブジェクトは、Javaスレッドが、次の三つの方法を中心に作成され、スレッドクラスまたはサブクラスのインスタンスでなければなりません。

Threadクラスを継承する方法

ステップ1から継承するクラス定義Thread、クラス、および、クラスのオーバーライドrunこの方法は、タスクを完了するためにスレッドを表す、方法を

ステップ2スレッドオブジェクトを作成するために作成されThreadたクラスのサブクラスのインスタンスを

ステップ3は、 2段階のオブジェクトの呼び出しから作成されstartたスレッドを起動する方法

/**
 * @author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @description: 通过继承 Thread 类的方式创建线程
 * @since JDK 1.8
 */
public class CreateThreadByExtendsThread extends Thread {

  @Override
  public void run() {
    IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + " " + i));
  }

  public static void main(String[] args) {
    CreateThreadByExtendsThread threadOne = new CreateThreadByExtendsThread();
    CreateThreadByExtendsThread threadTwo = new CreateThreadByExtendsThread();
    CreateThreadByExtendsThread threadThree = new CreateThreadByExtendsThread();

    threadOne.start();
    threadTwo.start();
    threadThree.start();
  }

}
复制代码
、Runnableインタフェースを達成するための第二の方法

ステップ1は、実装するクラス定義Runnableのインタフェースを、次にインターフェイス実装run方法を、この方法は、タスクを完了するためにスレッドを意味します

ステップ2作成するためのRunnableクラス・インタフェースのインスタンスを、そして例としてその使用Thraed作成するコンストラクタパラメータThreadオブジェクトクラスを、オブジェクトは実際のスレッドオブジェクトであります

ステップ3呼び出し元のスレッドオブジェクトのstartメソッドは、スレッドを開始します

/**
 * @author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @description: 通过实现 Runnable 接口的方式创建线程
 * @since JDK 1.8
 */
public class CreateThreadByImplementsRunnable implements Runnable {

  @Override
  public void run() {
    IntStream.rangeClosed(1, 10).forEach(i -> System.out.println(Thread.currentThread().getName() + " " + i));
  }

  public static void main(String[] args) {
    CreateThreadByImplementsRunnable target = new CreateThreadByImplementsRunnable();
    new Thread(target, "thread-one").start();
    new Thread(target, "thread-two").start();
    new Thread(target, "thread-three").start();
  }

}
复制代码
呼び出し可能インターフェースを実現するには、3つの方法

ステップ1実装するクラス定義Callable、インターフェイス、およびインターフェイス実装call方法を、この方法は、タスクを完了するためのスレッドを示し、値を返します

ステップ2作成してCallable使用して、クラスインターフェイスのインスタンスをFutureTaskラップするクラスをCallable対象に、FutureTaskオブジェクトがカプセル化しCallable、オブジェクトのcallメソッドの戻り値を

ステップ3および使用FutureTaskなどのオブジェクトをThraedの作成引数のコンストラクタThreadオブジェクト、およびオブジェクトの呼び出しstartスレッドを起動する方法を

ステップ4コールFutureTaskオブジェクトのgetメソッドは、スレッドの実行が終了した後の戻り値を取得します

/**
 * @author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @description: 通过实现 Callable 接口的方式创建线程
 * @since JDK 1.8
 */
public class CreateThreadByImplementsCallable implements Callable<Integer> {

  @Override
  public Integer call() {
    AtomicInteger count = new AtomicInteger();
    IntStream.rangeClosed(0, 10).forEach(i -> {
      System.out.println(Thread.currentThread().getName() + " " + i);
      count.getAndIncrement();
    });

    return count.get();
  }

  public static void main(String[] args) {
    CreateThreadByImplementsCallable target = new CreateThreadByImplementsCallable();
    FutureTask<Integer> futureTask = new FutureTask<>(target);

    IntStream.rangeClosed(0, 10).forEach(i -> {
      System.out.println(Thread.currentThread().getName() + " 的循环变量 i 的值" + i);
      if (i == 8) {
        new Thread(futureTask, "有返回值的线程").start();
      }
    });

    try {
      System.out.println("有返回值线程的返回值:" + futureTask.get());
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  }

}
复制代码

それを見ることができる以上により、実際には、実装することにより、Runnableインタフェースと実装をCallable基本的に同じ方法でこれら二つのスレッドのインタフェースを作成するために、実現の使用RunnableCallableするときモードインタフェースがスレッドを作成するには、スレッドクラスはインターフェイスを実装も継承することができ、他のクラス(PS:Java 单继承决定)。このように、複数のスレッドが同じ共有できるtargetオブジェクトを、その複数のスレッドがリソースと同じような状況に対処するための理想的です。もう一つのポイントは、それは、継承を使用しているThreadあなたは、現在のスレッドにアクセスする必要がある場合は、あなたが複数のスレッドを作成して、簡単な、などの準備をするとき、あなたが使用する必要はありませんThread.currentThread()直接使用方法、this現在のスレッドを得ることを。あなたが作成した場合、頻繁に実際のプロジェクトで消費閉じスレッドを作成するために、これらの3つの方法の使用は、システムリソースのパフォーマンスに影響を与え、そしてあなたがプールにスレッドプールのスレッドスレッドバックを使用できない場合は、スレッドプールからの時間がかかるので、私たちのプロジェクトの開発は主にスレッドプールを使用し、スレッドプールは、これら2つのを見てとることができたJavaスレッドプールを() Javaスレッド・プール(II)

スレッドのいくつかの状態

:スレッドが実行の動的なプロセスであり、それはまた、Javaでの農産物の死へのプロセスを、持っている、スレッドの完全なライフサイクルは、次の5つの状態の総含ん新しい状態(新)を使用する場合はnew、キーワードおよびThread作成したクラスまたはサブクラスをスレッドは、入力されたスレッドオブジェクトの後に、新建状态それおよびその他のJavaだけでJVM割り当てメモリにより、オブジェクトとそのメンバーの変数値を初期化し、そして、それは、オブジェクトの呼び出しにまでこの状態のままになりますstart方法。

レディ状態(Runnableを)スレッド・オブジェクトと呼ばれるstart方法の後に、準備完了状態にスレッド。レディスレッドは、スケジューリングのためのJVMスケジューラを待って、レディキューに配置されます。いつでも即応の状態をスレッドはCPUスケジューリングによって実行することができます。

実行状態(実行)レディ状態の実行がCPUスケジューリングによって実行されている場合は、あなたが実行できるrunメソッドを、スレッド状態のスレッド。最も複雑を実行中のスレッド、それがなることができ阻塞状态就绪状态そして死亡状态スレッドになることに注意してください运行状态だけ前の状態就绪状态

ブロックされた(ブロック)スレッドが実行した場合、理由は動作を停止し、CPUの使用を放棄し、一時的にいくつかの理由でブロックされた状態になるsleepsuspendとの他の方法、リソースの解放を占領した後、スレッド运行状态入ります阻塞状态再進入デバイスを得るために睡眠時間やリソースの終わりを待っています就绪状态障害物は、次の3つに分けることができます。

  1. ブロックを待っている中で运行状态、スレッドの呼び出しwait方法は、スレッドが入ります等待阻塞状态
  2. 同期のブロッキングスレッド取得のsynchronizedロックは同期が失敗した別のスレッドによって使用されているので、同期ロックは、スレッドが入ります同步阻塞
  3. 他のブロックされた呼び出し元のスレッドによってsleep、またはjoinI / O要求を発行する場合、スレッドは、ブロッキング状態になります。場合はsleep、タイムアウト、join待機しているスレッドが終了または満了し、またはI / O処理が完了すると、スレッドバック就绪状态

死の状態(デッド)におけるA 运行状态、完成スレッド実行run方法、または他の終了条件が発生するため、スレッドが入るでしょう死亡状态ライフサイクルのスレッド終わり。以下のように種々の状態によって表される循環より多くのスレッドは以下のとおりです。

スレッド状態transfer.png

一般的な方法をスレッド

共通の糸源に係る方法は、一つのから継承され、二つのカテゴリーに分けることができObject、以下のように、クラスメソッド:

方法 説明
公共の最終ネイティブ無効通知() それが入るように、このオブジェクトのモニター上のシングルスレッド待機を覚まします就绪状态
公共の最終ネイティブ空のnotifyAll() それが入るように、このオブジェクトのモニターで待機中のすべてのスレッドを覚まします就绪状态
公共の最終無効待機() ・現在のスレッドがあるしましょう等待阻塞状态、別のスレッドがオブジェクトの呼び出しまで、notifyメソッドまたはnotifyAllメソッドを現在のスレッドが目覚め、それが開催されたロックを解除します
公共の最終ネイティブ無効待機(長いタイムアウト) ・現在のスレッドがあるしましょう等待阻塞状态、別のスレッドがオブジェクトの呼び出しまで、notifyメソッドまたはnotifyAllメソッドを、現在のスレッドが目を覚まします
公共の最終無効待ち時間(長いタイムアウト、int型またはnanos) ・現在のスレッドがあるしましょう等待阻塞状态、別のスレッドがオブジェクトの呼び出しまで、notifyメソッドまたはnotifyAllメソッドまたはいくつかの他のスレッドの割り込み現在のスレッド、または一定の時間を実際の現在のスレッドが目覚め超えました

もう一つは、Thread次のように、クラス定義の方法:

方法 説明
公共の静的なネイティブ無効収量() 現在実行中のスレッドオブジェクトを一時停止し、他のスレッドを実行し、yieldこの方法は、ロックを解放しません
公共の静的なネイティブ無効スリープ(ロングミリ秒) スリープ(サスペンド)にスレッドが現在指定されたミリ秒数内で実行され、sleepこの方法は、ロックを解除していません
公共の最後のボイド(参加) プログラム実行フロー内の他のスレッドを呼び出すときjoinまでの方法は、呼び出し元のスレッドがブロックされるときjoin、実行のスレッドが完了しています
ます。public void割り込み() このスレッドを中断するには、このメソッドが呼び出されたときに、すぐに割り込みフラグは、スレッドに設定されています true
パブリック静的ブールが中断() Thread現在のスレッドが中断されたかどうかを示すブール値を返すクラスの静的メソッドinterruptedメソッドが外部に加えて、割り込みフラグを返すが、それはまた、(割り込みフラグがセットされているために約割り込みフラグをクリアfalse
パブリックブールisInterruptedを() Thread現在のスレッドが、中断されたかどうかを示すブール値を返すクラスインスタンスメソッドisInterrupted方法は、単に割り込みフラグが明確末端標識されない返します

スレッドの優先順位

各Javaスレッドは、オペレーティングシステムのスレッドスケジューリング順序を決定するのに役立ちます優先順位を持っています。Javaスレッドの優先度は、その値の範囲の整数です1(Thread.MIN_PRIORITY )~ 10(Thread.MAX_PRIORITY )デフォルトでは、各スレッドは、優先順位が割り当てられますNORM_PRIORITY(5)優先度の高いスレッドがプログラムに、より重要であり、優先度のスレッドを下げる前にプロセッサリソースを割り当てる必要があり、持っているThreadクラスが提供するsetPrioritygetPriority、スレッドの優先順位を変更し、取得するメソッド(という注:スレッドの優先度がスレッドを保証するものではありません実行の順序でなく、プラットフォームに非常に依存)。


参考記事

おすすめ

転載: juejin.im/post/5dec6544e51d4557ed541c92