プログラミング

Javaのスレッドと並列処理

スレッドと並列処理は、Javaにおける非常に重要なコンセプトであり、マルチタスクを効率的に処理するための強力なツールです。Javaでは、スレッドを使ってプログラムの複数の部分を同時に実行することができます。この技術は、特にパフォーマンスを向上させるために重要です。この記事では、Javaにおけるスレッドの基本的な概念から並列処理の実現方法、そして実際のコード例を交えて解説します。

スレッドとは?

スレッドとは、プロセス内で実行される最小の実行単位です。Javaでのスレッドは、通常のプログラムの流れとは独立して並行して実行されます。これにより、複数のタスクを同時に処理することが可能になります。

スレッドの作成方法

Javaでスレッドを作成するには、2つの方法があります:

  1. Threadクラスを拡張する方法
  2. Runnableインターフェースを実装する方法

1. Threadクラスを拡張する方法

最も基本的な方法は、Threadクラスを拡張し、そのrunメソッドをオーバーライドすることです。このメソッドにはスレッドが実行するコードを書きます。

java
class MyThread extends Thread { public void run() { System.out.println("スレッドが実行されています"); } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // スレッドの開始 } }

上記のコードでは、MyThreadクラスがThreadクラスを拡張し、runメソッドにスレッドが実行する処理を記述しています。startメソッドを呼び出すことでスレッドが実行されます。

2. Runnableインターフェースを実装する方法

もう一つの方法は、Runnableインターフェースを実装して、runメソッドを定義することです。この方法では、スレッドを別のクラスから独立して実行できるため、コードの再利用性が向上します。

java
class MyRunnable implements Runnable { public void run() { System.out.println("スレッドが実行されています"); } } public class Main { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); // スレッドの開始 } }

この方法の利点は、Runnableインターフェースを複数のスレッドで共有できる点です。異なるクラスで同じrunメソッドを使い回すことができます。

スレッドの同期

複数のスレッドが同じリソースにアクセスすると、データの整合性が保たれない場合があります。これを防ぐために、スレッド間で同期を行うことが重要です。

Javaでは、synchronizedキーワードを使ってメソッドやブロックを同期することができます。同期されたメソッドは、1つのスレッドのみが同時に実行できるようになります。

java
class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } public class Main { public static void main(String[] args) { Counter counter = new Counter(); // スレッドを作成して並列処理 Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); thread1.start(); thread2.start(); } }

この例では、incrementメソッドにsynchronizedをつけて、複数のスレッドが同時にこのメソッドを実行しないようにしています。

スレッドプール

スレッドの生成にはオーバーヘッドがかかるため、頻繁にスレッドを生成することは効率的ではありません。これを改善するために、Javaはスレッドプールを提供しています。スレッドプールを使用することで、あらかじめ決められた数のスレッドをプールしておき、タスクが来た際にその中のスレッドを再利用することができます。

java
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 100; i++) { executorService.submit(() -> { System.out.println("スレッドが実行されています"); }); } executorService.shutdown(); } }

このコードでは、ExecutorServiceを使ってスレッドプールを作成し、その中のスレッドを使って100回のタスクを並列に実行しています。タスクが完了した後、shutdownメソッドでスレッドプールを終了します。

並列処理の実現

並列処理とは、複数のタスクを並行して処理することです。Javaでは、ForkJoinPoolを使うことで、より効率的に並列処理を行うことができます。ForkJoinPoolは、大きなタスクを小さなタスクに分割し、それらを並列に実行します。

java
import java.util.concurrent.RecursiveTask; import java.util.concurrent.ForkJoinPool; public class Main { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(); // 再帰的にタスクを分割する RecursiveTask task = new RecursiveTask<>() { @Override protected Integer compute() { return 1 + 1; // 単純なタスク例 } }; System.out.println(pool.invoke(task)); // タスクの結果を取得 } }

ForkJoinPoolを使用すると、大規模な並列処理が効率的に実行できます。

結論

Javaにおけるスレッドと並列処理は、性能を最適化し、効率的なマルチタスク処理を実現するための強力なツールです。スレッドの作成方法、同期、スレッドプールの使用、そして並列処理を適切に活用することで、アプリケーションのパフォーマンスを大幅に向上させることができます。

Back to top button