SIMPLE

並列処理について

7zipが64スレッド以上の処理に対応した記事を見て並列処理について思いにふけったので記事作成しました。

並列処理について

プログラミングを基本シングルスレッドで動きますが、マルチスレッド(並列処理)を実装することで、配列の処理等が高速になります。

1. Javaの並列処理の基本サンプル

このコードでは ExecutorService を使って3つのタスクを並列に処理しています。

サンプルではただログを出しているだけですが、処理を3つ定義しておけば同時に3つの処理を実行できます。

スレッドプール(スレッドをため込む所)によりスレッド管理が容易になります。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ParallelExample {

    public static void main(String[] args) {
        // スレッドプール(固定数)を作成
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 3つのタスクを並列実行
        for (int i = 1; i <= 3; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("タスク " + taskId + " 開始 - スレッド: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000); // 疑似的な処理(2秒)
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("タスク " + taskId + " 終了 - スレッド: " + Thread.currentThread().getName());
            });
        }

        executor.shutdown(); // 全タスク終了後にスレッドプールを停止
    }
}

2. 配列の並列処理parallelStream()のサンプル

1のサンプルは処理を定義して同時実行ですが、2では配列に対して並列処理を実行します。

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {

    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave", "Eve");

        System.out.println("並列ストリーム処理開始");

        names.parallelStream()
             .forEach(name -> {
                 System.out.println("処理中: " + name + " - スレッド: " + Thread.currentThread().getName());
                 try {
                     Thread.sleep(1000); // 疑似的な重い処理
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
                 }
             });

        System.out.println("並列ストリーム処理終了");
    }
}

サンプル2の出力例

並列ストリーム処理開始
処理中: Alice - スレッド: ForkJoinPool.commonPool-worker-1
処理中: Bob - スレッド: ForkJoinPool.commonPool-worker-5
処理中: Charlie - スレッド: ForkJoinPool.commonPool-worker-3
処理中: Dave - スレッド: ForkJoinPool.commonPool-worker-2
処理中: Eve - スレッド: ForkJoinPool.commonPool-worker-4
並列ストリーム処理終了

出力例を見てわかる通り、配列に対して複数スレッドで並列処理を行っています。

ここで注意点で、配列の先頭から処理されずランダムに処理が行われます。

3. 並列処理のメリット

メリット

説明

高速化

複数の処理を同時に実行することで、全体の処理時間を短縮できる(特にI/O待ちが多い処理に有効)

応答性向上

GUIアプリやWebサーバでは、バックグラウンドで処理することでユーザーの操作性が向上

資源の有効活用

マルチコアCPUの性能を最大限に活かせる

4. 並列処理のデメリット

デメリット

説明

バグが発見しにくい

スレッド間のタイミングや競合状態(レースコンディション)は再現性が低く、デバッグが難しい

同期の必要

データを共有する場合は synchronizedLock などの同期制御が必要(これを怠るとバグの温床に)

オーバーヘッド

スレッド生成・切り替えにコストがかかり、少数タスクでは逆に遅くなることもある

リソース消費

スレッドを無制限に立てると、CPU・メモリを使いすぎてクラッシュの原因になる

牧野

RPCブログ管理者