Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

Java のプログラミングを進めていくと「マルチスレッド処理」や「並列処理」という言葉を耳にすることもあるでしょう。

複数の処理を同時に実行され、それらを短期間で処理することが求められるシステムでは、効率的に処理を行うマルチスレッドが求められ、また、不特定多数のユーザーからアクセスされるような Web アプリケーションでは、そもそもマルチスレッド処理は欠かせない技術です。

この記事では、Javaのスレッドを使って、複数の処理を同時に行う方法を解説してきます。

スレッドとは

「スレッド」は Java で処理を行う最小単位で、最低でもメインスレッドと呼ばれる1つのスレッドが作成され、そのスレッド上で Java の処理は実行されます。

1つのスレッドで実行できる命令は1であるため、例えば GUI でネットワーク通信を行うような処理の場合、通信が完了するまで次の命令が実行できないため、GUI が固まった状態の、いわゆるフリーズ状態になります。

そこで Java には Thread クラスや、その他マルチスレッド関連のクラスが用意されており、ネットワーク通信などの時間がかかる処理については、別で作成したスレッドで行わせ、メインスレッドの処理を止めないことで、GUI のフリーズ状態が回避でき応答性の良いアプリケーションを作れます。

また、Web アプリケーションにおいては、ユーザーからアクセス毎にスレッドを起動することで、同時に複数のリクエストを効率的に処理します。

逆に1つのスレッドだけで Webアプリケーションを処理していた場合、1つのリクエストを処理するのに3秒かかり、それが100人のユーザーから同時にアクセスされた場合、最後にリクエストを送信した人の処理が完了するのが 300秒後となり、とめも応答性がよいシステムとは呼べないようでしょう。

マルチスレッドを実装してみよう

マルチスレッドを行う実装として、もっとも基本的なのが Thread クラス継承したクラスを作成しそれを実行する方法です。継承したクラスにスレッド内で処理を行いたい命令を記述し、メインスレッドもしくは親となるスレッドから、 Thread クラス継承したクラスのインスタンスを作成し実行します。

実際に作ってみましょう。

まず、Thread クラス継承したクラスを作成します。スレッド内で行う命令は オーバーライドしたrunメソッドに記述します。

class SampleThread extends Thread {
    public void run() {
        System.out.println("スレッド開始");
        try {
            Thread.sleep(3000); //3秒処理を止める          
        } catch (InterruptedException e) {}
        System.out.println("スレッド終了");
    }
}

次にメインスレッドから、上で作成したクラスのインスタンスを作成し、スレッドを起動する処理を記述します。

class Main {
    public static void main(String[] args) {
        SampleThread t = new SampleThread();
        t.start();
        System.out.println("SampleThreadスレッドを起動");
    }
}

これだけで、複数のスレッドを起動する処理の完成です。サンプルコードを実行して結果を確認してみましょう。

実行結果
-----------------------------
SampleThreadスレッドを起動
スレッド開始
スレッド終了

このように、main 関数では、SampleThread クラスのスレッドの起動後、即座に次の命令が実行され、メインスレッドの処理がブロックされていないことが分かります。

処理の待ち合わせ

複数のスレッドを立ち上げると、それぞれスレッドは独立して命令を上から順に実行していきます。しかし時には○○の処理が終わるまでは、□□の処理は実行できないといった制約もあるでしょう。

複数のスレッド間で、このような処理の待ち合わせを行う場合は、waitnotify および notifyAll メソッドを使用することで、待ち合わせ処理を実装することができます。

wait メソッドは、他のスレッドから notify または notifyAll メソッドが呼び出されるまで、スレッドを一時停止するメソッドで、notify および notifyAll メソッドは、wait で一時停止させたレッドを再開させるためのメソッドです。

具体的なサンプルコードを見てみましょう。

class SampleThread extends Thread {
    public synchronized void run() {
        System.out.println("スレッド開始");
        try {
            wait(); // waitメソッドを呼び出して、notifyが呼ばれるまでスレッドを停止
        } catch (InterruptedException e) {}
        System.out.println("スレッド終了");
    }
}

class Main {
    public static void main(String[] args) {
        SampleThread t = new SampleThread();
        t.start();

        System.out.println("SampleThreadスレッドを起動");

        //3秒処理を止める 
        try {
            Thread.sleep(3000); 
        } catch (InterruptedException e) {}

        synchronized(t) {
            t.notify();    
        }
        System.out.println("notify()呼び出し");
    }
}

上のコードを実行した結果は次のとおりです。t.notify()が呼ばれるまでは、スレッドのwait()メソッドのところで処理が停止しているのが分かります。

実行結果
-------------------------
SampleThreadスレッドを起動
スレッド開始
notify()呼び出し
スレッド終了

これらのメソッドの詳細は、次の記事でも詳しく解説しています。

【関連記事】
【Java】wait・notifyを使ってスレッド間の待ち合わせを実装する

スレッドから戻り値を取得する

Thread クラスの run メソッドは void であり戻り値が返せません。スレッドから戻り値を取得する場合は、Callableクラスと Future インターフェイスを使用します。

まず Callable クラスを継承したクラスを作成します。String 型の値を返す Callableクラスであれば次のような形になります。

public class SampleCallable implements Callable<String> {
    //callメソッドをオーバーライドしてスレッドの処理を書く
    public String call(){
        return "Return Callable Value";
    }
}

Callable クラスのスレッドの呼び出しは、ExecutorServiceクラスを用いて行い、submit メソッドに実行するスレッドのインスタンスを指定します。

ポテパンダの一言メモ

スレッド処理の結果は、Future インターフェースで返ってきます。スレッドの処理が完了すると、Future#getメソッドでスレッドの戻り値が取得できます。

class Main {
    public static void main(String[] args) {  
        ExecutorService ex = Executors.newSingleThreadExecutor();
        //SampleCallableを実行
        Future<String> futureResult = ex.submit(new SampleCallable());      

        try {
            // Future型からスレッドの戻り値を取り出す
            String result = futureResult.get();
            System.out.println(result);
        }catch (Exception e){
            System.out.println(e);
        }
    }
}

まとめ

Java でスレッドを使用する方法を解説してきました。マルチスレッドプログラミングは、プログラミング学習でつまずきやすいポイントでもあるため、しっかりと理解しておきましょう。

【関連記事】
volatile修飾子でJavaのスレッド変数を制御する方法

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。