Javaスレッドの例
Javaスレッドの例へようこそ。プロセスとスレッドは、実行の基本的な単位です。並行プログラミングは、Javaスレッドにより関心があります。
処理
プロセスは独立した実行環境であり、プログラムやアプリケーションとして見ることができます。しかしながら、プログラム自体は複数のプロセスを内包しています。Javaランタイム環境は、さまざまなクラスやプログラムをプロセスとして含んだ単一のプロセスとして実行されます。
スレッド
スレッドは軽量プロセスと呼ばれることがあります。スレッドは作成に必要なリソースが少なく、プロセス内に存在しており、プロセスのリソースを共有します。
Javaスレッドの例
すべてのJavaアプリケーションには少なくとも1つのスレッド、つまりメインスレッドがあります。メモリ管理、システム管理、信号処理など、バックグラウンドで実行される他の多くのJavaスレッドが存在しますが、アプリケーションの観点からは、メインスレッドが最初のJavaスレッドであり、そこから複数のスレッドを作成できます。マルチスレッディングとは、単一のプログラム内で2つ以上のスレッドが同時に実行されることを指します。コンピュータのシングルコアプロセッサは一度に1つのスレッドしか実行できず、タイムスライシングはプロセスとスレッド間でプロセッサ時間を共有するためのOSの機能です。
Javaのスレッドの利点
-
- 日本語では次のように言い換えることができます:
Javaのスレッドはプロセスと比べて軽量であり、スレッドの作成には時間とリソースが少なくかかります。
スレッドは親プロセスのデータとコードを共有します。
スレッド間のコンテキスト切り替えは通常、プロセス間の切り替えよりもコストが低くなります。
スレッド間の通信はプロセス間の通信よりも比較的容易です。
Javaには、プログラム上でスレッドを作成するための2つの方法があります。
-
- Java.lang.Runnableインターフェースの実装。
- Java.lang.Threadクラスの拡張。
Javaのスレッドの例 – Runnableインターフェースを実装
クラスを実行可能にするためには、java.lang.Runnableインターフェースを実装し、public void run()メソッドで実装します。このクラスをThreadとして使用するには、この実行可能なクラスのオブジェクトを渡してThreadオブジェクトを作成し、その後start()メソッドを呼び出して別のスレッドでrun()メソッドを実行します。ここに、Runnableインターフェースを実装したJavaスレッドの例があります。
package com.scdev.threads;
public class HeavyWorkRunnable implements Runnable {
@Override
public void run() {
System.out.println("Doing heavy processing - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Doing heavy processing - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
Javaのスレッドの例 – Threadクラスを拡張したもの
私たちは、java.lang.Threadクラスを拡張して独自のJavaスレッドクラスを作成し、run()メソッドをオーバーライドすることができます。その後、そのオブジェクトを作成し、start()メソッドを呼び出してカスタムのJavaスレッドクラスのrunメソッドを実行することができます。以下に、Threadクラスを拡張する方法を示すシンプルなJavaスレッドの例をご覧ください。
package com.scdev.threads;
public class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("MyThread - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
ここに、Javaスレッドを作成し実行する方法を示したテストプログラムがあります。
package com.scdev.threads;
public class ThreadRunExample {
public static void main(String[] args){
Thread t1 = new Thread(new HeavyWorkRunnable(), "t1");
Thread t2 = new Thread(new HeavyWorkRunnable(), "t2");
System.out.println("Starting Runnable threads");
t1.start();
t2.start();
System.out.println("Runnable Threads has been started");
Thread t3 = new MyThread("t3");
Thread t4 = new MyThread("t4");
System.out.println("Starting MyThreads");
t3.start();
t4.start();
System.out.println("MyThreads has been started");
}
}
上記のJavaスレッドの例プログラムの出力は次のとおりです。
Starting Runnable threads
Runnable Threads has been started
Doing heavy processing - START t1
Doing heavy processing - START t2
Starting MyThreads
MyThread - START Thread-0
MyThreads has been started
MyThread - START Thread-1
Doing heavy processing - END t2
MyThread - END Thread-1
MyThread - END Thread-0
Doing heavy processing - END t1
一度スレッドを開始すると、その実行はOSの時間分割の実装に依存し、私たちはそれらの実行を制御することはできません。ただし、スレッドの優先度を設定することはできますが、その場合でも優先度が高いスレッドが最初に実行されることを保証するものではありません。上記のプログラムを複数回実行すると、スレッドの開始と終了にはパターンがないことがわかります。
実行可能(な) vs スレッド
クラスが単にスレッドとして実行される以上の機能を提供する場合は、Runnableインターフェースを実装してスレッドとして実行する方法を提供する必要があります。クラスの唯一の目標がスレッドとして実行される場合は、Threadクラスを拡張することができます。複数のインターフェースの実装をサポートするため、Runnableの実装が好まれます。Threadクラスを拡張すると、他のクラスを拡張することはできません。ヒント: スレッドは値を返さないことに気づいたかもしれませんが、スレッドが処理を実行し、その結果をクライアントプログラムに返す場合は、Java Callable Futureを確認してください。更新情報: Java 8以降、Runnableは関数型インターフェースであり、無名クラスの代わりにラムダ式を使用してその実装を提供することができます。詳細については、Java 8の関数型インターフェースをご覧ください。