Java マルチスレッドを実装するには、主に 4 つの方法があります。
① Thread クラスを継承し、Runnable インターフェイスを実装します。
② Callable インターフェイスを実装し、 FutureTask ラッパー Thread スレッドを通じて作成します。
③ ExecutorService と Callable を使用します。
④ Future で結果を返すマルチスレッドを実装します。
最初の 2 つのメソッドには、その後の戻り値がありません。スレッドが実行され、後の 2 つのメソッドの種類には戻り値があります。
Thread クラスは、本質的には Runnable インターフェイスを実装するインスタンスであり、スレッドの例。 Thread クラスの start() インスタンス メソッドを使用することが、スレッドを開始する唯一の方法です。 run() メソッドを実行する新しいスレッドは、ネイティブ メソッドである start() メソッドを呼び出すことによって開始されます。この方法でマルチスレッドを実装するのは非常に簡単で、独自のクラスを通じて Thread を直接拡張し、run() メソッドをオーバーライドすることで、新しいスレッドを開始し、独自に定義した run() メソッドを実行できます。例:
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();
クラスが別のクラスを拡張している場合、Thread を直接拡張することはできません。この時点で、Runnable インターフェイスを実装できます。
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
MyThread を開始するには、最初に Thread をインスタンス化し、独自の MyThread インスタンスを渡す必要があります:
MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();
実際には、Runnable ターゲット パラメータが に渡されるとき、 Thread、Thread の run() メソッドは target.run() を呼び出し、JDK ソース コードを参照します:
public void run() { if (target != null) { target.run(); } }
FutureTask ラッパーを通じて Thread スレッドを作成します
Callable インターフェイス (メソッドは 1 つだけです) は次のように定義されています:
public interface Callable<V> { V call() throws Exception; } public class SomeCallable<V> extends OtherClass implements Callable<V> { @Override public V call() throws Exception { // TODO Auto-generated method stub return null; } }
Callable<V> oneCallable = new SomeCallable<V>(); //由Callable<Integer>创建一个FutureTask<Integer>对象: FutureTask<V> oneTask = new FutureTask<V>(oneCallable); //注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 //由FutureTask<Integer>创建一个Thread对象: Thread oneThread = new Thread(oneTask); oneThread.start(); //至此,一个线程就创建完成了。
ExecutorService、Callable、および Future を使用して、結果を返すスレッド
ExecutorService。Callable と Future の 3 つのインターフェイスは、実際には Executor フレームワークに属します。 JDK1.5では、結果を返すスレッドが新機能として導入され、戻り値を取得する手間がなくなりました。また、たとえ自分で実装したとしても、抜け穴がたくさんある可能性があります。
値を返すことができるタスクは、Callable インターフェイスを実装する必要があります。同様に、値を返さないタスクは Runnable インターフェイスを実装する必要があります。
Callable タスクの実行後、Future オブジェクトを取得できます。そのオブジェクトに対して get を呼び出すことで、Callable タスクから返される Object を取得できます。
注: get メソッドはブロックされています。つまり、スレッドは結果を返さず、get メソッドは永久に待機します。
スレッド プール インターフェイス ExecutorService と組み合わせると、結果が返される伝説的なマルチスレッドを実現できます。
JDK1.5 で検証されており問題ありません。以下に示す結果が返されるマルチスレッド テスト サンプルを直接使用できます。コードは次のとおりです:
import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; /** * 有返回值的线程 */ @SuppressWarnings("unchecked") public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("----程序开始运行----"); Date date1 = new Date(); int taskSize = 5; // 创建一个线程池 ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 创建多个有返回值的任务 List<Future> list = new ArrayList<Future>(); for (int i = 0; i < taskSize; i++) { Callable c = new MyCallable(i + " "); // 执行任务并获取Future对象 Future f = pool.submit(c); // System.out.println(">>>" + f.get().toString()); list.add(f); } // 关闭线程池 pool.shutdown(); // 获取所有并发任务的运行结果 for (Future f : list) { // 从Future对象上获取任务的返回值,并输出到控制台 System.out.println(">>>" + f.get().toString()); } Date date2 = new Date(); System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】"); } } class MyCallable implements Callable<Object> { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } public Object call() throws Exception { System.out.println(">>>" + taskNum + "任务启动"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "任务终止"); return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】"; } }
主な違いは、 Runnable インターフェイスには戻り値がありません。
Callable インターフェイスの call メソッドには戻り値があり、汎用の Runnable インターフェイスをサポートしています。run メソッドはランタイム例外をスローすることのみが可能であり、キャプチャして処理することはできません。
Callable インターフェイスの call メソッドを使用すると、例外をスローし、例外情報を取得できます
スレッド オブジェクトは、スレッドを開始せずに run メソッドを呼び出します。オブジェクトのみがメソッドを呼び出します。
スレッド オブジェクトは、start を呼び出してスレッドを開き、jvm に run メソッドを呼び出して、開いたスレッドで実行させます。start メソッドを呼び出すと、スレッドが開始され、スレッドが準備完了状態になります。 run メソッドはスレッドの通常のメソッド、またはメインスレッドで実行されます。
スレッドに関連する基本メソッドには、wait、notify、notifyAll、sleep、join、yield などが含まれます。
Thread wait (wait) ) これを呼び出します メソッドのスレッドは待機状態に入り、別のスレッドからの通知を待つか中断された場合にのみ戻ります。wait() メソッドを呼び出した後、オブジェクトのロックが解放されることに注意してください。したがって、wait メソッドは通常、同期メソッドまたは同期コード ブロックで使用されます。
スレッド スリープ (スリープ) sleep は現在のスレッドをスリープさせます。wait メソッドとは異なり、sleep は現在占有されているロックを解放しません。sleep(long) はスレッドを TIMED-WATING 状態にします。 wait() メソッドは、現在のスレッドを待機状態にします。
スレッド イールド (yield) イールドは、現在のスレッドに CPU 実行タイム スライスを譲り渡し、CPU をめぐって他のスレッドと再競合させます。タイムスライス。一般に、優先度の高いスレッドは CPU タイム スライスの競合に成功する可能性が高くなりますが、これは絶対的なものではなく、一部のオペレーティング システムはスレッドの優先度に敏感ではありません。
スレッド割り込み (割り込み) スレッドの割り込みは、スレッドに通知信号を与えることを目的としており、これはスレッド内の割り込みフラグに影響します。このため、このスレッド自体は状態 (ブロック、終了など) を変更しません。
Join は、他のスレッドが join() メソッドを終了するのを待ち、他のスレッドが終了するのを待って、現在のスレッドのスレッドの join() メソッドが実行されると、現在のスレッドはブロッキング状態に変化し、別のスレッドに戻って終了します。現在のスレッドは再びブロッキング状態から準備完了状態に変化し、スレッドの好意を待ちます。 CPU。###
スレッドウェイクアップ (通知) Object クラスの Notice() メソッドは、このオブジェクト モニターで待機している単一のスレッドをウェイクアップします。すべてのスレッドがこのオブジェクトで待機している場合、スレッドの 1 つがウェイクアップするために選択されます。この選択は任意であり、実装の決定が行われたときに発生し、スレッドは、現在のスレッドがこのオブジェクトのロックを放棄するまで、ウェイクアップされたスレッドの実行を続行できるようになるまで、wait() メソッドの 1 つを呼び出してオブジェクトのモニター上で待機します。目覚めたスレッドは、オブジェクト上でアクティブに同期している他のすべてのスレッドと通常の方法で競合します。もう 1 つの同様のメソッドは、同じモニター上で待機しているすべてのスレッドを起動する、notifyAll() です。
① 異なるクラスから wait(): Object クラスから; sleep(): Thread クラスから;
② ロックの解放について wait(): 待機処理中にロックを解放する; sleep(): 待機中にロックを解放しない
③ 使用範囲: wait():同期する必要がある コードブロック内で使用; sleep(): どこでも使用可能;
④ 例外をキャッチするかどうか wait(): 例外をキャッチする必要がない; sleep(): 例外をキャッチする必要がある;
マルチスレッドの原則: マルチスレッドは並行して実行されます。 CPU の場合、ある時点で 1 つのプログラム、つまり同時に 1 つのプロセスしか実行できず、CPU はこれらのプロセスを継続的に切り替え、各スレッドは 1 回ずつ実行されます。 CPU の実行速度が人間の感覚に比べて速すぎるため、CPU は複数のプロセスをローテーションして実行しますが、あたかも複数のプロセスが同時に実行されているように感じられます。
CPU は複数のプロセスを切り替えますが、プログラムを開きすぎると、CPU が各プロセスに切り替えるまでの時間も長くなり、マシンの動作が遅くなったように感じられます。マルチスレッドを合理的に使用すると効率が向上しますが、過度に使用しても効率は向上しません。
マルチスレッド技術は、主にプロセッサ ユニットでのマルチスレッド実行の問題を解決し、プロセッサ ユニットのアイドル時間を大幅に短縮し、プロセッサ ユニットのスループット能力を向上させることができます。
以上がJavaでマルチスレッドを実装するにはどのような方法がありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。