スレッドの実験 その7Advertisementスレッド間の通信
wait()とnotify()ってメソッドでデッドロックとか例外を回避することができる。
スレッドでwait()を実行すると、そのスレッドはどこかのスレッドがnotify()するまで待ち状態になる。 悪い例。
public class Test{
public static void main(String args[]){
Intstack ints = new Intstack();
Pushthread put = new Pushthread(ints);
Popthread pot = new Popthread(ints);
put.start();
pot.start();
}
}
//スタックにデータをプッシュするスレッド
class Pushthread extends Thread{
Intstack intStc;
public Pushthread(Intstack s){
intStc = s;
}
public void run(){
for(int i = 0; i < 10; i++){
intStc.push((int)(Math.random() * 1.0) + 1);
System.out.println((i+1) + "回目のプッシュ");
try{
Thread.sleep((int)(Math.random()*100));
}catch(InterruptedException e){}
}
}
}
//スタックからデータをポップするスレッド
class Popthread extends Thread{
Intstack intStc;
public Popthread(Intstack s){
intStc = s;
}
public void run(){
for(int i = 0; i < 10; i++){
System.out.println(intStc.pop() + " : "
+ (i+1) + "回目のポップ");
try{
Thread.sleep((int)(Math.random()*100));
}catch(InterruptedException e){}
}
}
}
//スタックを管理するクラス
class Intstack{
private static int s[] = new int[10];
private static int sp = 0;
//データ格納:排他制御付き
public synchronized void push(int i){
s[sp] = i;
sp++;
}
//データ取り出し:排他制御付き
public synchronized int pop(){
sp--;
return s[sp];
}
}
結果
1回目のプッシュ
1 : 1回目のポップ
2回目のプッシュ
1 : 2回目のポップ
java.lang.ArrayIndexOutOfBoundsException: -1
at Intstack.pop(th.java:65)
at Popthread.run(th.java:42)
java.lang.ArrayIndexOutOfBoundsException: -1
at Intstack.push(th.java:58)
at Pushthread.run(th.java:21)
例外発生。何も入ってない所からデータを取り出そうとしたからダメ。この場合の例外は配列に負の数のインデックスでアクセスしたから発生した。 wait() notify()を使う
wait()とnotify()で回避。
wait()されたスレッドはキューに入って待ち状態になる。それからnotify()でキューから取り出されて実行可能状態になる。 wait()してnotify()を忘れるとずっと待ち状態となり、プログラムが停止することになる。注意。
public class Test{
public static void main(String args[]){
Intstack ints = new Intstack();
Pushthread put = new Pushthread(ints);
Popthread pot = new Popthread(ints);
put.start();
pot.start();
}
}
class Pushthread extends Thread{
Intstack intStc;
public Pushthread(Intstack s){
intStc = s;
}
public void run(){
for(int i = 0; i < 10; i++){
intStc.push((int)(Math.random() * 1.0) + 1);
System.out.println((i+1) + "回目のプッシュ");
try{
Thread.sleep((int)(Math.random()*100));
}catch(InterruptedException e){}
}
}
}
class Popthread extends Thread{
Intstack intStc;
public Popthread(Intstack s){
intStc = s;
}
public void run(){
for(int i = 0; i < 10; i++){
System.out.println(intStc.pop() + " : "
+ (i+1) + "回目のポップ");
try{
Thread.sleep((int)(Math.random()*100));
}catch(InterruptedException e){}
}
}
}
class Intstack{
private static int s[] = new int[10];
private static int sp = 0;
//データ格納:排他制御付き
public synchronized void push(int i){
if(sp >= s.length){
try{
wait(); //popされるまで待ち
}catch(InterruptedException e){}
}
s[sp] = i;
sp++;
notify(); //wait()解除
}
//データ取り出し:排他制御付き
public synchronized int pop(){
if(sp <= 0){
try{
wait(); //pushされるまで待ち
}catch(InterruptedException e){}
}
sp--;
notify(); //wait()解除
return s[sp];
}
}
結果。
1回目のプッシュ 1 : 1回目のポップ 2回目のプッシュ 1 : 2回目のポップ 3回目のプッシュ 1 : 3回目のポップ 4回目のプッシュ 1 : 4回目のポップ 5回目のプッシュ 1 : 5回目のポップ 6回目のプッシュ 1 : 6回目のポップ 7回目のプッシュ 8回目のプッシュ 1 : 7回目のポップ 9回目のプッシュ 1 : 8回目のポップ 10回目のプッシュ 1 : 9回目のポップ 1 : 10回目のポップもっと複雑だとnotifyAll()とか使わないと、プログラムがずっと停止したままになっちゃう場合もあるから要注意。臨機応変に。 Advertisement |
ショートカット・634・634ブログ ・このカテゴリのトップページに戻る ・Incubator(Pukiwiki) ・634ラボ UIコレクションギャラリー ZO-3ジェネレーター サイト検索Y!ログール |