Next: 14 待ちと通知のメソッド
Up: ソフトウェア第三 講義資料 Java入門,宣言,インタフェース,パッケージ,スレッド
Previous: 12.5 スタティックな同期メソッド
次に,CubbyHoleクラスのデータを生成するProducerクラス
と,それを消費するConsumerクラスの例で,それぞれが
独立のスレッドで走るというProducer-Consumerプログラムを考える.
// ProducerConsumerTest.java
public class ProducerConsumerTest {
public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}
ProducerクラスはThreadのサブクラスで,
そのrunメソッドは,オブジェクト内部に
保存しているCubbyHoleオブジェクトに対して
10個の数値を乱数で生成される待ち時間ごとに
ひとつづつputする.
// Producer.java
public class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" +
this.number
+ " put: " + i);
try {
sleep((int)(Math.random() * 100));
} catch (InterruptedException e) { }
}
}
}
Consumerクラスは,Producerにも保存されて
いるCubbyHoleオブジェクトから10個の数値を
待ち時間無く順にgetする.
// Consumer.java
public class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumer #" +
this.number
+ " got: " + value);
}
}
}
CubbyHoleクラスは,以下のようになる.
CubbyHoleのcontents,availableデータのように,privateがついているデータは
そのクラスからのみアクセス可能なものとなる.
// CubbyHole.java
public class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
// wait for Producer to put value
wait();
} catch (InterruptedException e) { }
}
available = false;
// notify Producer that value has been
// retrieved
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
// wait for Consumer to get value
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
// notify Consumer that value has been set
notifyAll();
}
}
もし,getとputメソッドをwhile文でなく
次のようにすると,もし,availableがfalseで
Producerが何もputしていないという状態が起こった場合,
getメソッドは何も返せなくなる.
また,Consumerが値をgetする前にProducerが
putを呼んでしまうと,synchronizedされている
getメソッドは何もできなくなってしまう.
そのため,waitメソッドとnotifyまたはnotifyAllメソッドを
使う.
public synchronized int get() { // won't work!
if (available == true) {
available = false;
return contents;
}
}
public synchronized void put(int value) { // won't work!
if (available == false) {
available = true;
contents = value;
}
}
実行は以下のようになる.
% java ProducerConsumerTest
Producer #1 put: 0
Consumer #1 got: 0
Consumer #1 got: 1
Producer #1 put: 1
Producer #1 put: 2
Consumer #1 got: 2
Consumer #1 got: 3
Producer #1 put: 3
Consumer #1 got: 4
Producer #1 put: 4
Producer #1 put: 5
Consumer #1 got: 5
Consumer #1 got: 6
Producer #1 put: 6
Consumer #1 got: 7
Producer #1 put: 7
Producer #1 put: 8
Consumer #1 got: 8
Consumer #1 got: 9
Producer #1 put: 9
ここでは,getとputのメソッドにsynchronizedキーワードが
ついている.
synchronizedメソッドがあるオブジェクトに対して実行されると
そのメソッドが修了するまで,そのオブジェクトに適用可能な
メソッドのうち,synchronizedメソッドは同時には実行できなく
なる.今の場合,あるCubbyHoleオブジェクト(cubbyhole)に
対してputメソッドが実行中には,他のスレッドがそのオブジェクトに
大してputメソッドやgetメソッドを実行できなくなる.
synchronizedがついていないメソッドは実行が可能.
ここで,getとputがputされた後に確実にgetを行うという
同期を取るために,
クラスObjectで定義されている
waitメソッドとnotifyAllメソッドを使っている.
generated through LaTeX2HTML. M.Inaba 平成18年5月7日