スレッドを作成する4つの方法(詳細解析)


スレッドの作成方法の本質は2つあります:(ただし、細分化は4つあります)1.Threadクラスを継承する方法2.Runnableを実現する方法
方法一:Threadクラスを継承する1.カスタムクラスMyThreadはThreadクラスを継承する.2.MyThreadクラスでrun()メソッドを書き換える.3.スレッドオブジェクトを作成します.4.スレッドを開始します.注意:1、スレッドを起動するにはrun()メソッドではなくstart()メソッドを使用します2、スレッドを複数回起動することはできません2、スレッドを複数回起動することはできません2:Runnableインタフェースを実現します1.カスタムクラスMyRunnableでRunnableインタフェースを実現します2.run()メソッドを書き換える3.MyRunnableクラスのイメージを作成します4.Threadクラスのオブジェクトを作成しますステップ3で作成したオブジェクトを構築パラメータとして渡す5.スレッド方式3を起動する:CallableとFutureを使用してスレッドを作成するのはRunnableインタフェースとは異なり、Callableインタフェースはcall()メソッドをスレッド実行体として提供し、call()メソッドはrun()メソッドよりも強力である.
』call()メソッドには戻り値があります
』call()メソッドは、放出異常を宣言することができる
Java 5は、Callableインタフェースにおけるcall()メソッドの戻り値を表すFutureインタフェースを提供し、FutureインタフェースにFutureインタフェースとRunnableインタフェースを実現する実装クラスFutureTaskを提供する.この実装クラスは、Futureインタフェースとして機能し、Threadクラスのtargetとして機能する.Futureインタフェースでは、関連するCallableタスクを制御するためのいくつかの共通の方法が定義されています.
boolean cancel(boolean mayInterruptIfRunning):ビューは、Futureに関連付けられているCallableタスクをキャンセルします.
V get():Callableのcall()メソッドの戻り値を返します.このメソッドを呼び出すとプログラムがブロックされ、サブスレッドが終了するまで待たなければ戻り値が得られません.
V get(long timeout,TimeUnit unit):Callableのcall()メソッドの戻り値を返し、最大でtimeout時間をブロックし、指定された時間を経てTimeoutExceptionを放出しなかった
boolean isDone():Callableタスクが完了したらTrueに戻る
boolean isCancelled():Callableタスクが正常に完了する前にキャンセルされた場合は、Trueに戻ります.
関連する概念を説明した後、戻り値のあるスレッドを作成して起動するには、次の手順に従います.
1.Callableインタフェースのインプリメンテーションクラスを作成し、call()メソッドを実装し、そのインプリメンテーションクラスのインスタンスを作成します(java 8からLambda式を使用してCallableオブジェクトを直接作成できます).
2.Callableオブジェクトのcall()メソッドの戻り値をカプセル化したFutureTaskクラスを使用してCallableオブジェクトをパッケージします.
3.FutureTaskオブジェクトをThreadオブジェクトのtargetとして使用してスレッドを作成して起動する(FutureTaskがRunnableインタフェースを実現しているため)
4.FutureTaskオブジェクトのget()メソッドを呼び出し、サブスレッド実行終了後の戻り値を取得
    :

public class Main {

  public static void main(String[] args){

   MyThread3 th=new MyThread3();

   //  Lambda     Callable  

     //  FutureTask    Callable  

   FutureTask future=new FutureTask(

    (Callable)()->{

      return 5;

    }

    );

   new Thread(task,"       ").start();//      Callable          

    try{

    System.out.println("       :"+future.get());//get()     ,            

    }catch(Exception e){

    ex.printStackTrace();

   }

  }

}

**         **
      Java         。
                      ,         ,      ,               。

*/
方法4:スレッドプールを使用してスレッドを作成するExecutorフレームワークなど
1.5後に導入されるExecutorフレームワークの最大の利点は,タスクのコミットと実行をデカップリングすることである.タスクを実行する人はTaskをはっきり説明して提出するだけです.このTaskがどのように実行されたのか、誰に実行されたのか、いつ実行されたのか、提出された人は気にしないでください.具体的には、最も一般的なスレッドプールThreadPoolExecutorなどのExecutorServiceにCallableオブジェクトをコミットすると、Futureオブジェクトが得られ、Futureオブジェクトのgetメソッドが実行結果を待つように呼び出されます.Executorフレームワークの内部にはjava.util.cocurrentパッケージの下でスレッドの起動、実行、閉じるを制御するスレッドプールメカニズムが使用されており、同時プログラミングの操作を簡素化できます.したがって、Java 5以降では、Threadのstartメソッドを使用するよりもExecutorを使用してスレッドを起動する方が管理しやすく、効率が良い(スレッドプールで実現し、コストを節約する)ほか、この逃走問題を回避するのに役立つ点があります.コンストラクタでスレッドを起動すると、別のタスクがコンストラクタが終了する前に実行される可能性があるため、初期化されたオブジェクトの半分にエクストラクタを使用してコンストラクタにアクセスする可能性があります.Executorフレームワークには、スレッドプール、Executor、Executors、ExecutorService、CompletionService、Future、Callableなどがあります.Executorインタフェースでは、Runableインタフェースを実装したクラスであるタスクを実行するRunableインスタンスを受信するメソッドexecute(Runnable command)が定義されています.ExecutorServiceインタフェースはExecutorインタフェースから継承され、マルチスレッドをより豊富に実現する方法を提供します.たとえば、ExecutorServiceは独自の方法をオフにし、1つ以上の非同期タスクの実行状況を追跡するためにFutureを生成する方法を提供します.ExecutorServiceのshutdown()メソッドを呼び出して、ExecutorServiceをスムーズに閉じることができます.このメソッドを呼び出すと、ExecutorServiceは新しいタスクの受け入れを停止し、コミットされたタスクの実行が完了するのを待つことになります(コミットされたタスクは、2つのクラスに分けられます.1つは実行済みで、もう1つは実行が開始されていません).コミットされたすべてのタスクが実行されると、ExecutorServiceが閉じます.したがって,このインタフェースを用いてマルチスレッドを実装および管理するのが一般的である.ExecutorServiceのライフサイクルには、実行、停止、終了の3つのステータスがあります.作成すると実行状態に入り、shutdown()メソッドが呼び出されるとクローズ状態になります.これは、ExecutorServiceが新しいタスクを受け入れなくなったことを意味しますが、コミットされたタスクを実行しており、コミットされたタスクが完了すると終了状態になります.shutdown()メソッドを呼び出さないと、ExecutorServiceは常に実行状態にあり、新しいタスクを受信し続け、新しいタスクを実行します.サーバ側は通常、それを閉じる必要がなく、常に実行すればいいです.
-----------------------------------------------------------4つのスレッド作成方法の比較-------------------------------
Runnableを実装する方法とCallableインタフェースを実装する方法は基本的に同じであるが,後者がcall()を実行する方法には戻り値があり,後者のスレッド実行体run()方法には戻り値がないため,この2つの方法を1つの方法とThreadクラスを継承する方法との差としてまとめることができる.
1、スレッドはRunnableまたはCallableインタフェースを実装するだけで、他のクラスを継承することもできます.
2、このようにして、複数のスレッドは1つのtargetオブジェクトを共有することができ、マルチスレッドが同じリソースを処理する場合に非常に適している.
3、しかしプログラミングは少し複雑で、現在のスレッドにアクセスする必要がある場合、Thread.currentThread()メソッドを呼び出す必要があります.
4.Threadクラスを継承するスレッドクラスは他の親を継承できない(Javaシングル継承決定).
5、前の3種類のスレッドが作成して閉じると頻繁にシステム資源を消費して性能に影響するが、スレッドプールを使用するとスレッドを使用しない時にスレッドプールに戻すことができ、使用する時にスレッドプールから取ることができ、プロジェクト開発では主にスレッドプールを使用する
注意:最初の3つでは、インタフェースを実装する方法でマルチスレッドを作成することが一般的に推奨されています.