- ベストアンサー
質問:スレッドについて学習中の初心者がコンパイルエラーに遭遇
- 現在、独学でスレッドについて学習しています。プログラムを作成し、指定時間経過後に他のスレッドに通知する動作を実現したいと思っていますが、コンパイルエラーが発生しています。
- エラーの内容は、型の開始が不正、識別子がない、シンボルを解釈できないといったもので、参考にしている模範解答とは大きく異なっているため、正しいやり方かどうか不安です。
- 初心者であるため、正しい答えと乖離したプログラムを書いているかもしれません。どなたか正しいやり方を教えていただけないでしょうか?
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>そのメソッドにアクセスできるスレッドは一つに限定されるで >そのメソッドの中(while(!str.equals("empty"))の判定)には >他のメソッドはアクセスできないのではないのでしょうか? 確かにsynchronizedされたメソッドにはいると、そのメソッドを持つインスタンスはLockされ他のスレッドからはアクセスできません。 しかし、メソッドに入ったスレッドがLockしたインスタンスのwait()を呼ぶと、そのスレッドが取得したLockは強制的に放棄されられ、スレッドは待機状態になります。 こうなると、インスタンスのLockは解除され、他のスレッドもアクセス可能になるようです。 >こう考えるとsynchronizedとwait()が同じメソッドに置くのは >意味がないように思えるのですが、いかがでしょうか? 私も、基本的に今回のようなプログラムではwait()は、必要ないと思います。 synchronizedとsleep()で充分可能で、スレッド間通信を行う理由があまりないように思えます。 参考URLにwait()やnotifyAll()のサンプルがありますので、参考になさってください。
その他の回答 (2)
- PecoPlus
- ベストアンサー率76% (144/188)
それっぽく、動くサンプルを作ってみました。 初めてなので、変かも知れません。 おかしいところがあったら、ベテランの方、ご指摘願います。 コンパイルするときは、全角スペースを半角スペースに変換してからにしてください。 class Pro { private String str = "empty"; public synchronized void res(String str2) { while(!str.equals("empty")) { try { //strがemptyでない場合、スレッドは取得したLockを放棄されられ、 //待機プールに沈む。 wait(); } catch (InterruptedException ex) { ex.printStackTrace(); } //待機から復帰しても、strがemptyでないと、ここからでられない。 } try { str = str2; System.out.println(str); Thread.sleep(((int)(Math.random() * 10) * 50) + 500); str = "empty"; Thread.sleep(3000); //待機プールに沈んでいるスレッドを起こす。 notifyAll(); } catch (InterruptedException ex) { ex.printStackTrace(); } } } class User extends Thread { String str; Pro pro; User(String str, Pro pro) { this.str = str; this.pro = pro; } public void run() { for (int i = 0; i < 5; i++) { pro.res(str); } } } public class NewRikai6{ public static void main(String args[]){ Pro pro = new Pro(); User user1 = new User("user1",pro); user1.start(); User user2 = new User("user2",pro); user2.start(); } }
お礼
回答、ありがとうございます。質問させて頂いてからもずっと考えているのですが、そもそもsynchronizedを宣言するとそのメソッドにアクセスできるスレッドは一つに限定されるでそのメソッドの中(while(!str.equals("empty"))の判定)には他のメソッドはアクセスできないのではないのでしょうか?こう考えるとsynchronizedとwait()が同じメソッドに置くのは意味がないように思えるのですが、いかがでしょうか?(わかりにくい文章で申し訳ないです。res()が終了する時にはstrには"empty"が代入されているのでwhileで判定する必要は無いのではないかということです)
- PecoPlus
- ベストアンサー率76% (144/188)
こんばんは。 aleckさんの質問を機会に私もwait()とnotifyAll()の勉強をすることにしました。 私も覚えたてなので、よろしくお願いします。 さて、aleckさんのソースを見ましたが、構文的に明らかにおかしいところがあります。 try{ synchronized void res(String str){ this.str = str; array[0] = str; System.out.println(array[0]); Thread.sleep(((int)(Math.random() * 10) * 50) + 500); array[0] = "empty"; Thread.sleep(3000); notifyAll(); } } メソッドの宣言をtryで囲ってしまっています。 メソッドの外に命令文が来ていて、これはおかしいです。 あと、ProクラスがThreadを継承している必要もないと思います。 それと、Userクラスのrun()メソッド内の try{ if((pro.array[0]).equals("empty")){ pro.res(str2); } else{ wait(); } } ここでUserクラスのwait()を呼んでしまっています。 Proクラスのwait()を呼ばなくては行けないのではないでしょうか? それにwait()を呼ぶのは、ObjectのLockを取得してからのはずです。 synchronizedされたresメソッドに入って初めて、Lockが取得できるので、wait()はresメソッド内で使う必要があると思うのですが、どうでしょう?
お礼
早速の回答ありがとうございます。PecoPlusさんの説明で胸のモヤモヤがすっきりしたように思います。wait()の考え方が間違っていたようです。他のスレッド(user1)がメソッドにアクセスしているときにスレッド(user2)を待機させるものと思っていました。そうではなくアクセスしているスレッド(user1)を途中で待機させ、user2に通知(notify)するものなんですね?参考URLも参考にさせていただきます。ありがとうございました。