Javaエンジニア・プログラマ向けの技術情報・業界ニュースをお届けします。

  1. FEnetJava
  2. Javaコラム
  3. Java入門
  4. Javaのwaitでマルチスレッドプログラミングに挑戦しよう!|sleepとwaitの違いとは?

Javaのwaitでマルチスレッドプログラミングに挑戦しよう!|sleepとwaitの違いとは?

  • Java入門
公開日時:
Javaのwaitでマルチスレッドプログラミングに挑戦しよう!|sleepとwaitの違いとは?
この記事でわかること
    システム
    エンジニア
    Javaのマルチスレッドプログラミングのことについて、詳しく教えていただけませんか。
    プロジェクト
    マネージャー
    ''わかりました。それでは、少し詳しく解説いたしましょう。

    Javaのwaitとは?


    マルチスレッドプログラミングと聞いてわかる方はどの程度いらっしゃるのでしょうか。マルチスレッドとは複数の処理を表し、プログラムを平行で動作させることを意味します。普通にプログラムをすると1つの流れで順番に処理しますが、マルチスレッドなら複数の流れを同時に処理できるのです。

    そういったマルチスレッドで、他のスレッドの処理が終わるまで待ちたい場合があります。Javaではそういう時には、Objectクラスのwaitメソッドで待つことができるのです。この記事ではその具体的な方法について解説します。

    Javaのwaitを使用するサンプル

    Javaのwaitを使うサンプルが以下です。この後、内容について全て解説します。

    public class ThreadTest extends Thread {
    private int number;
    private Object lock;

    public ThreadTest(int n, Object o) {
    number = n;
    lock = o;
    }

    public void run() {
    try {
    System.out.println(number + “”番のスレッド開始。””);

    for (int i = 0; i < 10+(5*number); i++) {
    System.out.println(number + “”番は”” + i + “”回目の作業中。””);
    Thread.sleep(100);
    }

    switch (number) {
    case 0:
    synchronized (lock) {
    System.out.println(number + “”番はwaitします。””);
    lock.wait();
    System.out.println(number + “”番はwaitが解除されました。””);
    }
    break;
    case 1:
    synchronized (lock) {
    lock.notify();
    System.out.println(number + “”番はnotifyをコールしました。””);
    }
    break;
    }
    } catch (InterruptedException e) {
    }
    }
    }

    public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();
    ThreadTest test0 = new ThreadTest(0, lock);
    ThreadTest test1 = new ThreadTest(1, lock);
    test0.start();
    test1.start();
    }

    Threadクラスを継承すればマルチスレッド処理を行える

    それではこのJavaサンプルを頭から説明します。まずThreadTestクラスですが、これはThreadというクラスを継承しています。これでThreadTestクラスはマルチスレッド処理を行うことができるのです。

    ThreadTestクラスはコンストラクタでnumberとlockというフィールドを設定しています。numberがスレッドの番号、lockはロック用オブジェクトを格納しています。

    マルチスレッド処理はtry~catchで囲む

    lock用オブジェクトは、マルチスレッド間の連携処理に必要になります。これは後で説明します。

    runというメソッドは親のThreadクラスの同名のメソッドをオーバーライドしています。マルチスレッド処理ではこのrunメソッド内の記述が平行で処理されます。

    runの中の処理はtry~catchで囲まれていますが、マルチスレッド関連のメソッドを使用する時はThread.interruptで割り込まれてInterruptedExceptionが発生する可能性があるため、これが必要になります。

    sleepとwaitの違い

    runの中ではまず「〇番のスレッド開始。」と表示した後、forループで疑似的に作業をしています。numberの値が大きいほど多くループしますが、これは後でwait関連の処理を行うためです。

    forループでは「〇番は△回目の作業中。」と表示した後にThread.sleepでしばらく待っています。sleepとwaitの違いは、sleepはスレッドのロックが不要でwaitはロックが必要という違いがあります。またwaitはsleepと違い、他のスレッドから待ち状態を解除されることを前提として使用します。

    synchronizedで排他してからwaitする

    forループとsleepによる疑似的な作業が終わった後、switch文でnumberが0か1によって違う処理を行います。0の場合はwaitをコールして待ちます。この時lockに入れたロック用オブジェクトをsynchronizedで排他して、そのオブジェクトのwaitを呼び出して待ちます。

    この時に使用するロック用オブジェクトは目印のようなものだと思ってください。waitを解除するには、このロック用オブジェクトを排他しているスレッドを解除すれば良いので、処理がわかりやすくなります。

    notifyもsynchronizedで排他して行う

    次にswitch文でnumberが1だった場合です。ロック用オブジェクトをsynchronizedで排他して、そのオブジェクトのnotifyをコールしています。これでこのロック用オブジェクトでwaitしているスレッドがその状態から解除されるのです。

    次にmainメソッドを解説します。こちらではまずlockにObject型のロックオブジェクトを生成しています。waitやnotifyはObject型にあるメソッドで、ロックオブジェクトはどんな型でもかまいません。ロックを行うためだけに存在するオブジェクトなのです。

    サンプルプログラムの実行結果

    mainメソッドの続きです。ロックオブジェクトの生成の次はThreadTestのインスタンスを2つ生成しています。コンストラクタで0番と1番として、ロックオブジェクトも渡しています。そして両方のstartをコールしています。これはThreadTestの親クラスのThreadのメソッドです。

    これで2つのスレッドが走り出します。このJavaサンプルの実行結果は以下のようになります。

    0番のスレッド開始。
    1番のスレッド開始。
    1番は0回目の作業中。
    0番は0回目の作業中。
    (中略)
    0番は9回目の作業中。
    1番は9回目の作業中。
    0番はwaitします。
    1番は10回目の作業中。
    1番は11回目の作業中。
    1番は12回目の作業中。
    1番は13回目の作業中。
    1番は14回目の作業中。
    1番はnotifyをコールしました。
    0番はwaitが解除されました。

    waitとnotifyはペアで使用する

    この実行結果を見ると分かるように、2つのスレッドは平行で同時に処理されています。そしてThreadTestのrunメソッド内のfor文で設定したように、0番の方が先に終わってwait状態になり、その後も1番はしばらく処理を行います。

    そして1番がnotifyをコールすると、0番のwait状態が解除されていることが結果からわかります。このようにwaitとnotifyはペアで使用するJavaの機能なのです。

    notifyAllとjoin

    なおnotifyはwaitしているスレッドを1つ解除します。2つ以上あった場合も解除されるのは1つだけです。waitしている全てのスレッドを解除したい場合は、notifyAllを使用しましょう。

    なおmainメソッド内でstartしたスレッドの処理を待ちたい場合は、Javaサンプルのmainの最後に以下を追加してください。これで両方のスレッドが終わるまで待つことが出来ます。

    try {
    test0.join();
    test1.join();
    System.out.println(“”全ての処理が終わりました。””);
    } catch (InterruptedException e) {
    }

    システム
    エンジニア
    Javaのwaitとsleepの違いもよく分かりました。
    プロジェクト
    マネージャー
    Javaのwaitをマスターすれば、マルチスレッドの処理を行う時に便利に活用でますよ。

    マルチスレッドプログラミングではwait・notify・joinを駆使しよう

    Javaのwaitやnotify、joinの使い方を解説しましたがご理解頂けましたでしょうか。

    Javaのマルチスレッドプログラミングの奥は深いですが、マスターすれば高度なJavaアプリケーションを作ることができます。

    Javaエンジニアとしてレベルアップするために是非身につけてください。

    FEnetJava・Javaコラムは株式会社オープンアップシステムが運営しています。
    株式会社オープンアップシステムロゴ

    株式会社オープンアップシステムはこんな会社です

    秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
    数多くのエンジニアが集まります。

    秋葉原オフィスイメージ
    • スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。

    • 充実した研修制度

      充実した研修制度

      毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。

    • 資格取得を応援

      資格取得を応援

      スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。

    • 東証プライム上場企業グループ

      東証プライム上場企業グループ

      オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。

      安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。

    株式会社オープンアップシステムに興味を持った方へ

    株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。

    年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
    まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。

    株式会社オープンアップシステムへのご応募はこちら↓
    株式会社オープンアップシステムへのご応募はこちら↓

    Java新着案件New Job