Javaについて徹底解説!

Javaでプログラムを一時停止、Thread.sleepの使い方と仕組みを解説

大石 英人

プログラムの中で少し待ちたいことはよくあります。Javaでプログラムを「待たせる」方法の一つに、指定した時間だけ停止させるThread.sleepがあります。

ここで「停止」と一言で書きましたが、Javaプログラミングの初心者が「停止ってこういうことじゃないかな?」と漠然と思っている状態とは多分違います。きちんと理解するには、Javaのマルチスレッドプログラミングの知識が少しだけ必要になるのです。

この記事では、プログラムを待たせるThread.sleepの使い方と、Javaでのスレッドやマルチスレッドのちょっとした知識を、初心者向けにお伝えします。

※この記事のサンプルは、Java 11の環境で動作確認しています


1.Thread.sleepでプログラムの動作を一時的に止める

1-1.Thread.sleepの使い方

Javaプログラムの動作を一時的に止めるには、Threadクラスのstaticメソッドsleepを使うのが簡単です。引数のlongへは、止める時間をミリ秒で指定します。なお、ナノ秒単位でもできるようにオーバーロードされたメソッドもあります。

Thread.sleepの使い方は以下のような感じです。

sleepはtry-catchとセットになるのが普通です。sleepは検査例外(catchしないとコンパイルエラーになる例外)InterruptedExceptionthrowするかもしれないからです。ただ、sleep中にこの例外が発生しても何もすることはないのが普通なので、catchが空なのもごく普通です。

1-2.本当に止まっているか測ってみよう

では、本当に止まっているか測ってみます。確かに10秒後の時刻が二回目に表示されましたね。

実行結果


2.【参考】Javaでのスレッド・マルチスレッドの考え方

サンプルのとおり、Thread.sleepを使うと一時的にプログラムの動きが止まります。では、なぜ、どういう仕組みで止まるのでしょうか。

それに、mainメソッドの中で、自分でスレッドなるモノを作って動かした覚えはありませんよね。でもThread.sleepをすると実際にプログラムが止まるのは事実です。では、どこの誰がそのスレッドを作って、スレッド上でプログラムを実行し、スレッドを一時的に止めているのでしょうか。

その理解には、Javaでのスレッドやマルチスレッドの考え方を学ぶ必要があります。この章では、Thread.sleepの動きを理解するために必要な最低限の知識を簡単にお伝えします。

2-1.Javaを実行すると必ず一つはスレッドが作られる

Javaが実行される時には必ず一つはスレッドがあります。そして、そのスレッドはJava仮想マシンが管理します。いわゆるメインスレッド(Main thread)と呼ばれるものがJava仮想マシンにより必ず作られ、そのスレッドがクラスのmainメソッドに書かれた処理を実行するのです。

例えば、mainメソッドがないクラスを無理矢理実行すると以下のようなエラーが出ます。その中にある“main”こそが、まさにメインスレッドのことなのです。

つまり、Thread.sleepを呼び出すということは、Java仮想マシンに今このプログラムを動かしているスレッドをちょっと止めてくれと依頼をすることです。これはJavaのライブラリの世界ではなく、もっと深い、Java仮想マシンの世界で行われます。ですから、Thread.sleepnativeメソッドだったりするのです。

2-2.Thread.sleepをしても、他のスレッドは動き続ける

Javadocにあるとおり、Thread.sleepで止まるのは現在実行されているスレッドつまりThread.sleepを呼び出したスレッドです。もし、別のスレッドを作って動かしていたなら、それらのスレッドは止まりません。Thread.sleepJavaのプログラム全体やJava仮想マシン自体を止めるものではないのですね。

そして、メインスレッドの実行が終わることと、Java仮想マシンの実行が終わることは、必ずしも同じことではありません。Java仮想マシンが終わるのは「全てのスレッド」が終わった時なので、メインスレッドとは別にスレッドを作って動かしっぱなしにしていれば、Java仮想マシンはずっと終わらないのです。

ですので、「mainメソッドが終わったはずなのに、どうにもJavaが終わらないなぁ」という事象が発生した場合は、できるならデバッガでスレッドの一覧を表示してみましょう。きっと、あなたが終了し忘れているスレッドがこっそり動いているはずですよ。

2-3.InterruptedExceptionは他のスレッドからの割り込みを表す

Javaのプログラムは全てJava仮想マシンの管理下にあります。それはスレッドも例外ではなく、スレッド間の通信をするメソッドにはJava仮想マシンが関わります。その一つが、別のスレッドから「割り込み」があったことをスレッドに伝えるThread.interruptです。

InterruptedExceptionは、スレッドが何かをしている時に別のスレッドから割り込みがあったよと、スレッドに教えてあげるためにあるものです。ですから、sleep以外にも例えばObject.waitによりスレッドが止まっている時も、他のスレッドからの働きかけによりInterruptedExceptionが発生しえます。

また、スレッドへの割り込みそのものは、sleepなどで止まっている状態でなくても発生しえます。ですから、割り込まれたかどうかをスレッド自身が把握するために、Thread.interruptedisInterruptedなどのメソッドが用意されているのです。


3.まとめ

Javaでプログラムの動きを一時的に止める時は、Thread.sleepを使ってミリ秒やナノ秒単位で止められます。動きが止まるのはThread.sleepを実行したスレッドだけで、もし他のスレッドを作って動かしていたなら、それらのスレッドは動き続けますので注意しましょう。

Javaでは、プログラム中でスレッドを作って使っているつもりがなくても、実はこっそり使っています。それがメインスレッドです。この知識があるのとないのとでは、Javaの動き方への理解が全然違います。何となくでもいいので、こういうことなんだと覚えておくと、役に立つことがあると思いますよ!!

なお、マルチスレッドはプログラムの性能を向上させる手段の一つです。ですが、ノンブロッキングI/Oなどのように、処理が終わったら呼び出すという仕組みも全体の性能向上のためには有力な方法です。プログラムのボトルネックの原因をしっかり把握し、最適な対応手段を選べるようになりたいですね。

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。