あるプロセス内で複数の独立した処理を実行するためには、そのプロセス内に複数個のスレッドを用意します。それらのスレッドは、OSからプロセスに割り当てられたリソース (メモリやCPU実行時間) を共有しつつ、独立した処理を進めます。具体的な実装方法には、Threadを継承する方法とRunnableインターフェースを実装する方法の二つがあります。以下の例ではThreadを継承する方法を採用しています。なお、Threadはjava.langパッケージに属しているため、こちらのページで書きましたように、importせずに使用できます。
sample.java
class MyThread extends Thread {
private int sleepTime;
public MyThread(int sleepTime) {this.sleepTime=sleepTime;}
public void run() { //runを実装して具体的な処理を記述
try {
for(int i=0; i<5; ++i) {
Thread.sleep(sleepTime);
System.out.println(sleepTime);
}
}
catch(InterruptedException ex) { //sleep中に発生しうる例外
ex.printStackTrace(); //InterruptedExceptionを捕獲できるようにする必要有
}
}
}
class Sample {
public static void main(String args[]) {
MyThread t1 = new MyThread(1000);
MyThread t2 = new MyThread(2000);
t1.start();
t2.start();
try {
t1.join(); //t1のrunが完了するまで待機
t2.join(); //t2のrunが完了するまで待機
System.out.println("Both t1 and t2 finished.");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
実行例
$ javac sample.java && java Sample
1000
2000
1000
1000
2000
1000
1000
2000
2000
2000
Both t1 and t2 finished.
先程のサンプルでは、完全に独立した処理を各スレッドが実行していました。今回は、共通のオブジェクトの参照を各スレッドに渡して連携して処理してもらいます。その際、リソースのメソッドにsynchronizedを修飾子として指定し、片方がリソースを使用している間はロックをかけ他方が利用できないようにします。リソースを使用する予定だが他方が終了してから使用したい場合は、wait()を呼びだして一時的にロックを解除します。また、リソースを使用し終わったスレッドはnotifyAll()でwait中の別のスレッドにその旨を連絡します。共通リソースを連携して処理するため、synchronizedを用いたマルチスレッドプログラミングを行うと、意図せずデッドロックが発生する危険性あることにも注意しましょう。
sample.java
class MyThread extends Thread {
private MyArr myArr;
private String name;
public MyThread(String name, MyArr myArr) {
this.name = name;
this.myArr = myArr;
}
public void run() {while(myArr.add(name));}
}
class MyArr {
private static final int SIZE=8;
private String arr[];
private int idx;
public MyArr() {
this.arr = new String[SIZE];
this.idx = 0;
}
public synchronized boolean add(String name) {
if(idx==SIZE) return false;
while(name.equals("odd") && idx%2==0
|| name.equals("even") && idx%2==1) {
try {
wait(); //ロックを解除し、notifyされるまで待機
}
catch(InterruptedException e){
e.printStackTrace();
System.exit(0);
}
}
if(idx==SIZE) return false;
arr[idx++]=name;
notifyAll(); //wait中の別スレッドに間もなく処理が完了することを連絡
return true;
}
public void display() {for(int i=0; i<SIZE; ++i) System.out.println(arr[i]);}
}
class Sample {
public static void main(String args[]) {
MyArr myArr = new MyArr();
MyThread t1 = new MyThread("odd", myArr);
MyThread t2 = new MyThread("even", myArr);
t1.start();
t2.start();
try {
t1.join();
t2.join();
myArr.display();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
実行例
$ javac sample.java && java Sample
even
odd
even
odd
even
odd
even
odd