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

マルチスレッド処理において、「A」の処理が完了するまで「B」の処理を待ち合わせるといったケースがあります。これを「スレッド間の待ち合わせ」と言い、並列で動作するスレッドを制御する上で重要な知識となります。

この記事では、Javaのwait, notify, notifyAllメソッドを使用して、マルチスレッド処理における待ち合わせを制御をする方法を解説します。

スレッド間の待ち合わせをする3つのメソッド

Javaでは、すべてのクラスのベースとなるObjectクラスに、スレッド間の待ち合わせ制御で使用する3つのメソッドが用意されています。

wait メソッド

waitメソッドは、別のスレッドからnotifyまたはnotifyAllメソッドが呼び出されるまで、スレッドを一時停止するメソッドです。

notify / notifyAll メソッド

notifyおよびnotifyAllは、waitで一時停止させておいたスレッドを再開させるためのメソッドです。

notifyは、ウェイトセットにあるスレッド1つを再開させるメソッドで、複数のスレッドがwaitで待機している状況では、再開するスレッドはJVMによってランダムに選択されます。

notifyAllは、waitで一時停止しているスレッドを全て再開するメソッドです。

ポテパンダの一言メモ

waitnotifyおよびnotifyAllメソッドを実行する場合は、synchronizedを使って、該当のオブジェクトのロックを取得しておく必要があります。

「wait」メソッドの使い方

最初は、waitメソッドの使い方を見ていきましょう。waitメソッドは、現在のスレッドを一時停止し、該当のオブジェクトに対しnotifyおよびnotifyAllメソッドが呼ばれるまで待機します。

synchronizedをメソッドに指定し、waitメソッドの呼び出し前に該当のオブジェクトのロックを取得していることも忘れないようしましょう。

また、スレッドに対する割り込みが入った時にInterruptedException例外が発生するため、これをcatchなどで処理します。

synchronized void sampleWait() {
  try {
    wait();
  } catch (InterruptedException e) {
    //例外処理
  }
}

上のサンプルコードは、thisのクラス・インスタンスに対するwaitメソッドの呼び出しですが、オブジェクトを指定してwaitメソッドを呼び出す場合は、synchronizedブロックで該当オブジェクトのロックを取得後、waitを呼び出します。

void sampleWait(obj) {
  synchronized(obj) {    
    try {
      obj.wait();
    } catch (InterruptedException e) {
      //例外処理
    }  
  }
}

タイムアウトを指定する

waitメソッドの引数にタイムアウト時間を指定すると、指定した時間まではスレッドを一時停止し、タイムアウト時間を過ぎてもnotifyまたはnotifyAllが呼び出されない場合は、スレッドを再開させます。

synchronized void sampleWait() {
  try {
    //タイムアウトを1000ミリ秒に指定して、waitメソッドを呼び出し
    wait(1000);
  } catch (InterruptedException e) {
    //例外処理
  }
}

「notify」メソッドの使い方

次は、waitでウェイトセットに入っているスレッドを再開させるnotifyメソッドの使い方を見ていきましょう。

waitメソッドを読んだスレッドはブロックされるため、別のスレッドを生成してnotifyメソッド呼び出します。またsynchronizedを指定してnotifyで再開させるオブジェクトのロックを獲得するのも忘れないようにしましょう。

synchronized void sampleNotify() {
  notify();
}
ポテパンダの一言メモ

notifyではInterruptedException例外をキャッチする必要はありません。

「notifyAll」メソッドの使い方

notifyAllnotifyと同様です。
synchronizedで再開させるオブジェクトのロックを獲得してからメソッドの呼び出しを行います。

synchronized void sampleNotify() {
  notifyAll();
}

wait / notifyを組み合わせて待ち合わせを実装

各メソッドの使用方法を確認したところで、waitnotifyを使ってスレッドの待ち合わせを実装するサンプルコードを見ていきましょう。

import java.util.*;
import java.util.concurrent.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    // 「wait」および「notify」でロックするオブジェクト
    private static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {

        DateTimeFormatter dtformat = DateTimeFormatter.ofPattern("HH:mm:ss");

        // スレッドプールの作成
        ExecutorService pool = Executors.newFixedThreadPool(5);

        // 別スレッドを生成し、wait()を呼びだし、notify()が呼ばれるまで待機
        pool.submit(() -> {
            synchronized(obj) {
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.printf("%s: スレッドが再開されました", dtformat.format(LocalDateTime.now()));
        });

        // 現在時刻を出力
        System.out.printf("%s: 開始\n", dtformat.format(LocalDateTime.now()));

        // ここで3秒間待機
        Thread.sleep(3000);

        // notifyの呼び出し
        synchronized(obj) {
            obj.notify();
        }

        // スレッドの終了を待機
        try {
            pool.shutdown();
            pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }    
}

上のコードを実行すると次のような結果となります。

実行結果
----------------------
00:10:12: 開始
00:10:15: スレッドが再開されました

まとめ

JavaのwaitnotifyおよびnotifyAllメソッドで、スレッド間の待ち合わせを実装する方法を解説してきました。

マルチスレッド処理においては、同時並行で複数の処理が実行されるため、最初は理解や考え方が難しいですが、何本かのサンプルコードを実際に自分の手で組んでみれば自然と身につくはずですので、是非挑戦してみましょう。

【関連記事】
【初心者向け】Javaのスレッド(Thread)・マルチスレッドとは?使い方も紹介!

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

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

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

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

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

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

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

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

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

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

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