こんにちは!フリーライターの中井です。
Javaにはスレッドの処理を一時停止させるsleepメソッドがあります。この記事では、
- スレッドとは?
- sleepメソッドとは?
- sleepメソッドの使い方
という基本的な内容から、
- スリープ中に割り込まれると例外が発生すること
- sleepメソッドは誤差が出ること
などの応用的な使い方に関しても解説していきます。
なお、Javaの記事については、こちらにまとめています。
スレッド(Thread)とは
スレッドとは、処理の実行単位の一つで、プログラムの初めから終わりまでの一連の流れのことを言います。
専門的な言い方になりますが、実はHello,Worldを出力するプログラムも一連のスレッドになります。
更にスレッドは、シングルスレッドとマルチスレッドの2種類に分かれます。
シングルスレッドとは?
シングルスレッドは、別名直列処理とも呼ばれています。
例えば、夏休みの宿題に英語の問題集と数学の問題集があるとします。
シングルスレッドの場合は英語の問題集をスタートさせて、終わってから数学の問題集をスタートします。
覚え方としては、初めの処理が終わってから次の処理をすると理解しておきましょう。
つまり、プログラムの始まりから終わりまでが一本道で処理されるのがシングルスレッドとなります。
マルチスレッドとは?
一方マルチスレッドは、別名並行処理とも呼ばれています。シングルスレッドと同じように夏休みの宿題で例えると、マルチスレッドの場合は英語の問題集と数学の問題集に同時に取り組みます。
覚え方としては、2つ以上の処理を並行して行うと理解しておきましょう。マルチスレッドを利用するには、
- 1. Threadクラスを継承するクラスを作成する
- 2. Threadクラスを継承するクラスでrunメソッドを実行する
- 3. Threadクラスを継承するクラスのインスタンスを生成する
- 4. 生成したインスタンスに対してstartメソッドを実行する
となります。以下にマルチスレッドを実行する簡単なサンプルを紹介します。
public class ThreadSample { public static void main(String[] args) { MultiThread1 mt1 = new MultiThread1(); MultiThread2 mt2 = new MultiThread2(); mt1.start(); mt2.start(); } } class MultiThread1 extends Thread { public void run() { for (int i = 0; i < 3; i++) { System.out.println("スレッド1 : " + (i + 1) + "回目"); } } } class MultiThread2 extends Thread { public void run() { for (int i = 0; i < 3; i++) { System.out.println("スレッド2 : " + (i + 1) + "回目"); } } }
実行結果
スレッド2 : 1回目 スレッド1 : 1回目 スレッド2 : 2回目 スレッド1 : 2回目 スレッド2 : 3回目 スレッド1 : 3回目
サンプルプログラムでは、マルチスレッドを行うためにThreadクラスを継承したMultiThread1クラスとMultiThread2クラスを作成し、mainメソッドからstartメソッドでスレッドを実行しています。
実行結果から分かるとおり、スレッドによる並行処理が実施されていることがわかりますね!
sleepメソッドとは
sleepメソッドとは、プログラムを一時停止するときに使用します。
とくにマルチスレッドで使用することが多いメソッドです。sleepメソッドの定義は以下のようになっています。
public static void sleep(long millis)
sleepメソッドを使用するメリットとして、マルチスレッドの並列処理で無限ループを実行していた場合、CPUの負荷が大きくなりリソースを消費してメモリリークなどPCの動作が重くなる要因となってしまいます。
そのため、マルチスレッドの処理中にsleepメソッドを使用して、処理を一時停止すればCPUの負荷を抑えられることができます。
sleepメソッドの使い方
ここでは実際にsleepメソッドの使い方を見ていきましょう。
以下にsleepメソッドを使用した簡単なサンプルを記述します。
public class JavaSleep { public static void main(String[] args) { try { System.out.println("5秒停止します"); Thread.sleep(5000); System.out.println("一時停止を解除しました。"); } catch(InterruptedException e){ e.printStackTrace(); } } }
実行結果
5秒停止します 一時停止を解除しました。
このプログラムではsleepメソッドを使って、処理を5秒間停止させています。例外にはtry-catch文で対処しています。
sleepメソッドのポイントは以下の2つです。
- sleepメソッドの引数はlong型を使用、単位はミリ秒(1000ミリ秒 = 1秒)
- sleepメソッドを使う場合には必ず例外処理をすること
マルチスレッドでsleepを実行
ここでは、マルチスレッドの並行処理でsleepメソッドを使用する方法を紹介しています。
実際のシステムでも、以下のサンプルのようにマルチスレッドでsleepメソッドを使用する機会は多いので、ぜひ覚えておきましょう。
public class ThreadSample { public static void main(String[] args) { MultiThread1 mt1 = new MultiThread1(); MultiThread2 mt2 = new MultiThread2(); mt1.start(); mt2.start(); } } class MultiThread1 extends Thread { public void run() { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); System.out.println("スレッド1 : " + (i + 1) + "回目"); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MultiThread2 extends Thread { public void run() { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); System.out.println("スレッド2 : " + (i + 1) + "回目"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
実行結果
スレッド1 : 1回目 スレッド2 : 1回目 スレッド1 : 2回目 スレッド2 : 2回目 スレッド1 : 3回目 スレッド2 : 3回目 スレッド1 : 4回目 スレッド2 : 4回目 スレッド1 : 5回目 スレッド2 : 5回目
サンプルではThreadクラスを継承したMultiThread1クラスとMultiThread2クラスでrun()メソッドでスレッドを実行し、for文の中でsleepメソッドを使用しています。
sleepメソッドの注意点
sleepメソッドの注意点は、以下の2つです。
- interruptedExceptionの例外が発生すること
- sleepメソッドでは精度が低く誤差が生じること
interruptedExceptionの例外に対処する方法
interruptedExceptionの例外は、sleepメソッドで待機中にinterruptメソッドで割り込みが発生したときに発生します。
必要に応じて例外に対処するプログラムを書いてください。interruptedExceptionの例外に対処する方法を覚えるために、次のソースコードで確認してみましょう。
public class JavaSleep extends Thread{ public void run(){ try { System.out.println("runメソッド:1秒停止します"); Thread.sleep(1000); } catch(InterruptedException e){ System.out.println("プログラムの割り込みが発生しました"); e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { JavaSleep js = new JavaSleep(); js.start(); Thread.sleep(500); js.interrupt(); } }
実行結果
runメソッド:1秒停止します プログラムの割り込みが発生しました java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at javasleep.JavaSleep.run(JavaSleep.java:11)
まずこのプログラムはrunメソッドが待機状態になるのを待つために500ミリ秒待機します。
その後interruptメソッドで待機中のrunメソッドに割り込み、interruptedExceptionの例外を発生させています。
sleepメソッドで誤差が発生する問題
sleepメソッドはプログラムを実行する環境によっては誤差が発生する場合があります。
そのため、高い精度が必要な処理では使わないようにしてください。次のプログラムで誤差を計測してみましょう。
public class JavaSleep { public static void main(String[] args) { try { for (int i = 0; i < 5; i++) { long start = System.currentTimeMillis(); Thread.sleep(1000); long stop = System.currentTimeMillis(); System.out.println((stop - start) + " [ms]"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
実行結果
1001 [ms] 1000 [ms] 1001 [ms] 1000 [ms] 1000 [ms]
プログラムの実行結果から、sleepメソッドで誤差が発生することを確認できました。
Threadクラスについてもっと知りたい方へ
紹介したようにThreadクラスを使用すれば、同時並行で処理を実行することが可能です。
実際のシステムでマルチスレッドを使用したプログラムは多いので、仕組みはぜひ覚えておきましょう。
この記事では紹介しきれなかったThreadクラスのいろいろな使い方を次の記事にまとめているので、ぜひ確認してください!
まとめ
この記事ではsleepメソッドの使い方について解説しました。
sleepメソッドで待機中にinterruptメソッドで割り込みを行うと、interruptedExceptionの例外が発生するので注意してくださいね。
もし、sleepメソッドの使い方を忘れてしまったらこの記事を確認してくださいね!