【Java】スレッドの基本
Javaのスレッドについて基本的なことをまとめておきます。
スレッド
Javaでは複数の処理を同時に並行して行うことができます。それぞれの処理の分岐のことをスレッドと言います。
スレッドの作り方
処理を分岐させてスレッドを作る方法は2つあります。
スレッドの作り方1
1つ目は、クラスライブラリのThreadクラスを継承したクラスを作り、そこに別スレッドで行いたい処理を書く方法です。 Threadクラスのサブクラスでrun()メソッドを定義すると、その内容がスレッドを新しく起動した時に行われる処理となります。
class クラス名 extends Thread { public void run() { // 新しく起動したスレッドで行いたい処理 } ... }
このクラスのインスタンスを作成し、start()メソッドを適用することによって、新しくスレッドが起動します。
例を見てみます。
Hello1.java
class Hello1 extends Thread { private String name; public Hello1(String name) { this.name = name; } public void run() { for(int i = 0; i < 3; i++) { System.out.println("Hello, " + this.name); } } }
Example1.java
class Example1 { public static void main(String[] args) { Hello1 hello = new Hello1("World"); hello.start(); // 新しいスレッド起動 for (int i = 0; i < 3; i++) { System.out.println("Main"); } } }
この2つを同じディレクトリに保存し、実行すると次のようになりました。
Main Main Main Hello, World Hello, World Hello, World
なんか、あんまり並列処理している感じがないですが...。実行環境によって出力される順番は変わると思います。
スレッドの作り方2
2つ目は、クラスライブラリのRunnableインターフェースを実装するクラスを作る方法です。 この場合はThreadクラスのインスタンスを作成してそれに対してstart()メソッドを適用することになります。
例を見てみます。
Hello2.java
class Hello2 implements Runnable { private String name; public Hello2(String name) { this.name = name; } public void run() { for(int i = 0; i < 3; i++) { System.out.println("Hello, " + this.name); } } }
Example2.java
class Example2 { public static void main(String[] args) { Hello2 hello = new Hello2("World"); Thread th = new Thread(hello); th.start(); // 新しいスレッド起動 for (int i = 0; i < 3; i++) { System.out.println("Main"); } } }
実行結果:
Main Main Main Hello, World Hello, World Hello, World
スレッドを一時停止する
sleep()メソッドを使います。オブジェクト.sleep(x)
とすることで処理がxミリ秒だけ停止します。
次の例はHello1.java
、Example1.java
のうち、Hello1.java
のrun()メソッドだけを書き換えたものです。エラー処理を書かないとコンパイルする時に怒られます。
Hello3.java
class Hello3 extends Thread { private String name; public Hello3(String name) { this.name = name; } public void run() { for(int i = 0; i < 3; i++) { try { this.sleep(1000); System.out.println("Hello, " + this.name); } catch(InterruptedException e) {} } } }
Example3.java
class Example3 { public static void main(String[] args) { Hello3 hello = new Hello3("World"); hello.start(); // 新しいスレッド起動 for (int i = 0; i < 3; i++) { System.out.println("Main"); } } }
実行結果:
Main Main Main Hello, World Hello, World Hello, World
それぞれのHello, World
が表示されるまでに1000ミリ秒=1秒が経過します。
他のスレッドが終了するまで待機する
join()メソッドを使います。あるオブジェクトに対してjoinメソッドを用いると、そのオブジェクトに関連づけられたスレッドが終了するまで待機し、それから以降の処理を行います。
Example1を改造した例です。
Hello4.java
class Hello4 extends Thread { private String name; public Hello4(String name) { this.name = name; } public void run() { for(int i = 0; i < 3; i++) { System.out.println("Hello, " + this.name); } } }
Example4.java
class Example4 { public static void main(String[] args) { Hello4 hello = new Hello4("World"); hello.start(); // 新しいスレッド起動 // hello に関連づけられたスレッドが終了するまで待機 try { hello.join(); } catch (InterruptedException e) {} for (int i = 0; i < 3; i++) { System.out.println("Main"); } } }
実行結果:
Hello, World Hello, World Hello, World Main Main Main
スレッドを同期させる
複数のスレッドが同じあるメソッドを呼び出す時、メソッドの呼び出しを同時に行わないようにすることを同期と言います。各スレッドは順番にそのメソッドの呼び出しを行うことになります。
そのようなメソッドを作りたいときは、メソッドの宣言時にsynchronized
とつけます。
アクセス指定子 synchronized 戻り値の型 メソッド名() {
…
}