【Java入門】waitの使い方(notify、notifyAllについても解説)

Javaのwaitは現在のスレッドを待機させたい場合に使用します。

スレッドを使用していると、他の処理が終わるまで現在のスレッドを待機させたい場合があります。

この記事では、そんなwaitについて以下の内容で解説していきます。


・waitとは
・notifyが呼び出されるまで待機
・notifyAllが呼び出されるまで待機
・Thread.sleepについて

今回はwaitについて、使い方をわかりやすく解説します!

なお、Javaの記事については、こちらにまとめています。

目次

waitとは?

waitメソッドが呼び出されると現在のスレッドが待機状態になります。

notifyメソッド、またはnotifyAllメソッドが呼び出されるまで待機します。

スレッドとは、「複数の処理を同時並行で行える機能」と考えるとよいかと思います。

このスレッドが一列で順番に処理されていくことを、「シングルスレッド」と言います。

これに対して、スレッドの列が2つ以上複数あり並列に同時進行で処理されていくことを「マルチスレッド」と言います。

マルチスレッドで、あるスレッドの処理が終了するのを別のスレッドが待機する必要がある場合に、このwaitメソッドを使います。

waitメソッドはjava.lang.Objectクラスのメソッドです。

以下のようにtry-catch文とあわせて使われます。

try {
    wait();
} catch (InterruptedException e) {
    e.printStackTrace();
}

notifyが呼び出されるまで待機

notifyメソッドで処理を再開する方法について解説します。

notifyメソッドはwaitメソッドが呼び出され待機状態のスレッドの中の1つを再開します。

複数のスレッドが待機している場合は、その中のどれか1つのスレッドを再開します。

どのスレッドを再開するか選択することはできません。

サンプルコードで確認しましょう。

class PrintClass {
    synchronized void threadWait() {
        System.out.println("待機を開始します");

        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("待機が終了しました");
    }

    synchronized void threadNotify() {
        notify();
        System.out.println("待機を終了させます");
    }
}

class ThreadWait extends Thread {
    private PrintClass pc;

    public ThreadWait(PrintClass pc) {
        this.pc = pc;
    }

    public void run() {
        pc.threadWait();
    }
}

class ThreadNotify extends Thread {
    private PrintClass pc;

    public ThreadNotify(PrintClass pc) {
        this.pc = pc;
    }

    public void run() {
        pc.threadNotify();
    }
}

public class WaitSample {

    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        ThreadWait tWait = new ThreadWait(pc);
        ThreadNotify tNotify = new ThreadNotify(pc);

        tWait.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        tNotify.start();
    }

}

実行結果:

待機を開始します
待機を終了させます
待機が終了しました

synchronized修飾子が付いたメソッドをメンバに持つオブジェクトはそのメソッドを実行している間、同じオブジェクト内のsynchronized修飾子が付いたメソッドからアクセスされないようにロックされます。

このサンプルコードでは、waitメソッドをメンバに持つオブジェクトtWaitのスレッドがスタートして待機状態が開始されます。

1000ミリ秒後にnotifyメソッドをメンバに持つオブジェクトtNotifyのスレッドがスタートして待機状態が終了します。

結果「待機が終了しました」と表示する処理が実行されています。

notifyAllが呼び出されるまで待機

notifyAllメソッドで処理を再開する方法について解説します。

notifyAllメソッドはwaitメソッドにより待機状態にある全てのスレッドの処理を再開します。

サンプルコードで確認しましょう。

class PrintClass {
    synchronized void threadWait() {
        System.out.println(Thread.currentThread().getName() + "の待機を開始します");

        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + "の待機が終了しました");
    }

    synchronized void threadNotifyAll() {
        notifyAll();
        System.out.println("全スレッドの待機を終了させます");
    }
}

class ThreadWait extends Thread {
    private PrintClass pc;

    public ThreadWait(PrintClass pc) {
        this.pc = pc;
    }

    public void run() {
        pc.threadWait();
    }
}

class ThreadNotify extends Thread {
    private PrintClass pc;

    public ThreadNotify(PrintClass pc) {
        this.pc = pc;
    }

    public void run() {
        pc.threadNotifyAll();
    }
}

public class WaitSample {

    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        ThreadWait tWait1 = new ThreadWait(pc);
        ThreadWait tWait2 = new ThreadWait(pc);
        ThreadWait tWait3 = new ThreadWait(pc);
        ThreadNotify tNotify = new ThreadNotify(pc);

        tWait1.start();
        tWait2.start();
        tWait3.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        tNotify.start();
    }

}

実行結果:

Thread-0の待機を開始します
Thread-2の待機を開始します
Thread-1の待機を開始します
全スレッドの待機を終了させます
Thread-0の待機が終了しました
Thread-1の待機が終了しました
Thread-2の待機が終了しました

このサンプルコードでは、waitメソッドをメンバに持つオブジェクトtWait1、tWait2、tWait3のスレッドがスタートしてそれぞれの待機状態が開始されます。

1000ミリ秒後にnotifyAllメソッドをメンバに持つオブジェクトtNotifyのスレッドがスタートして全てのスレッドの待機状態が終了します。

結果、それぞれのスレッドで「待機が終了しました」と表示する処理が実行されています。

synchronized修飾子やnotifyAllメソッドの使い方については、こちらでも詳しく解説しています。

ぜひ参考にしてください。

Thread.sleepについて

Threadクラスのsleepメソッドを使って一定時間停止させることもできます。

Thread.sleepメソッドの使い方については、こちらで詳しく解説していますので、ぜひ参考にしてください。

まとめ

ここでは、スレッドについてwaitメソッドの使い方やnotify、notifyAllメソッドの使い方について説明しました。

あるスレッドの処理が終了するのを別のスレッドが待機する必要がある場合に、waitメソッドを使います。

また、待機状態から処理を再開する場合にnotify、notifyAllメソッドを使います。

スレッドは使い始めの頃は慣れずに戸惑ったりすることも多くなるかもしれませんが、そんな場合はこの記事を何度も参考にして下さいね!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次