みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

synchronizedによる同期化について

Javaで開発しています。
synchronizedで同期化したく、サンプルを作ってみたのですが上手く同期化が出来ていないようなので質問しました。

以下プログラム

public class Synch{
public static void main(String[] args){
final Something obj = new Something();
new Thread(){
public void run(){
synchronized(this){
try{
obj.write();
}

catch(Exception e){
}notify();}
}
}.start();

new Thread(){
public void run(){
try{
obj.read();
}
catch(Exception e){
}
}
}.start();
}
}

class Something{
private int x = 10;
private int y = 100;

public synchronized void write(){
if(x < y){
System.out.println("write:x < y");
}
else if(x > y){
System.out.println("write:x > y");
}

for(int n = 0;n < 100;n++){
x++;
y++;
}
for(int m = 0;m < 150;m++){
y--;
}

if(x < y){
System.out.println("write:x < y");
}
else if(x > y){
System.out.println("write:x > y");
}
}
public synchronized void read(){
if(x < y){
System.out.println("read:x < y");
}
else if(x > y){
System.out.println("read:x > y");
}

}
}

このプログラムを実行すると、時々readのほうが先に表示されてしまいます。
実行環境はEclipse2.1.3です。

readが先に表示されるのは仕方のないことなのでしょうか?
それともプログラムがいけないのでしょうか?

ご存知の方いらっしゃいましたら教えて頂けないでしょうか。

不足がありましたら仰ってください。

投稿日時 - 2006-12-09 20:29:46

QNo.2590558

困ってます

質問者が選んだベストアンサー

マルチスレッドなプログラムには疎いので間違っていたらごめんなさい。syncronizedは実行の順序を指定するものではないので仕方ないと思います。

このプログラムでは最初のスレッドと二個目のスレッドは独立して動いて「同時にwriteとreadが実行されることはない」ですが、スレッドの作成順番に実行されることは保証されません。

具体的に何をしたらいいのか書くと、他に回答が付くかもしれません。

投稿日時 - 2006-12-10 22:52:56

お礼

crumさん、回答ありがとうございます。
返信が遅くなってすみません。

Javaの教本にあったプログラムをそのまま載せて実行していたのですが、その教本にはwrite()内でx=10,y=5を代入するだけでしたのでfor文で同じ事をさせてみたらどうなるか試していたらreadが先に表示されてしまったのでお聞きしました。

>スレッドの作成順番に実行されることは保証されません。
そうだったのですか・・・。てっきりされるものだと思っていました。

投稿日時 - 2006-12-12 03:49:20

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

syncronizedは排他するためのものであって順序制御はできません。あくまでOS(VM)のCPU割り当て次第です。要求・応答の同期をとる方法はいくつかありますが、
JDK1.5を使っているのなら、java.util.concurrentパッケージのAQS(順序つきセマフォ)を用いるのが並行処理プログラミングになじみのない方には理解しやすいのではないでしょうか?
あるいは、単純にこのプログラムを動かしたいだけであれば(つまり実際的な方法ではありませんが)、カウンタをもって、書き込んだ場合にインクリメント、読み込んだ場合にデクリメント(もちろんそれぞれの操作のあいだ排他は必要です)して、カウンタが0の間はreadしないで、CPUを浪費しないように一定間隔のスリープをいれるなどすれば、非常に原始的な同期を行うことはできます。
「Concurrency: State Models & Java Programs」とかが優れた入門書だと思います。

投稿日時 - 2006-12-12 01:57:52

お礼

gucciiさん、回答ありがとうございます。

concurrentについて調べてみたのですが、1.5から新しく追加されたみたいで知りませんでした。

>カウンタが0の間はreadしないで、CPUを浪費しないように一定間隔のスリープをいれるなどすれば、非常に原始的な同期を行うことはできます。
どうしても上手くいかなかったので、この方法でやっています。。。


>Concurrency: State Models & Java Programs」
一応拝見したのですが全て英語で理解できませんでした。
教えて頂いたのにすみません。

プログラムの順に実行されると思っていたのでなぜかなーと思っていました。
一応、謎が解けましたので〆させて頂きます。

投稿日時 - 2006-12-13 19:22:23