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

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

解決済みの質問

synchronized を施しているのに・・・

java初心者です。宜しくお願い致します。
あるスレッドがsynchronizedのメソッドを実行すると、そのメソッドの仕事は連続したひとかたまりの処理として実行される、と習いました。
なるほど、と思ったのですが、
自分で次のようなコードを書いてみると、そのようになりません。
ならない時もある、と言ったほうが正確でしょう。
具体的には、

0 1 別の処理 2

や、

0 別の処理 1 2

となったりします。
ご面倒でしょうが、コードを書きますので、解析して解りやすく教えて頂けると嬉しく思います。


class MyRunnable10 implements Runnable{
public synchronized void run(){
for(int i=0 ; i<3 ; i++){
System.out.print(i + " ");
}
}
}

class MyRunnable20 implements Runnable{
public void run(){
System.out.print("別な処理");
}
}

public class Exec2 {
public static void main(String[] args) {
Runnable m = new MyRunnable10();
Runnable m2 = new MyRunnable20();
Thread t1 = new Thread(m,"A");
Thread t2 = new Thread(m2);
t1.start();
t2.start();
}

}

投稿日時 - 2012-07-10 21:04:25

QNo.7583079

困ってます

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

>あるスレッドがsynchronizedのメソッドを実行すると、そのメソッドの仕事は連続したひとかたまりの処理として実行される

言葉としてはそういえますが、微妙な表現ですね……。

例えば、この例でいえば、ちゃんとrunメソッド内の処理はまとめて処理されています。ただし、これらはそれぞれが別のスレッドとして動いていますので、それらが同時に実行されれば両者の出力が交じり合う事になります。

「ひとかたまりに実行する」ということを、イコール「その間、他のスレッドは停止して待っている」と考えてはいけません。一連の処理を実行している間も、別のスレッドで処理が実行されていれば、それはそれで動き続けます。

「それじゃ、まとめて処理するってどういう意味なんだ?」と思うでしょう。これは、スレッドの処理ごとに考えるより、「オブジェクト」単位で考えたほうがわかりやすいです。

例えば、こんなクラスがあったとします。

class MyData {
int num = 0;
}

で、mainメソッド内でこのMyDataインスタンスを1つ作成し、MyRunnable10とMyRunnable20の両方のrun内で、この1つのインスタンスに同時にアクセスして値を書き換えたとしましょう。すると、MyRunnable10から値を書き換えた後、その値を利用するまでの間に、MyRunnable20が値を書き換えてしまっているかも知れませんね。

1つのオブジェクトに、同時に複数のスレッドがアクセスし値を操作すると、予想外の結果を引き起こします。したがって、例えばMyRunnable10がMyDataインスタンスを利用するなら、利用し終えるまで他のスレッドから一切アクセスできないようにする必要があります。これがsynchronizedです。

つまり、synchronizedは一連の処理をまとめて実行するというより、「排他的処理」のためのものなのです。あるスレッドがオブジェクトにアクセスしている間、別のスレッドがそのオブジェクトに触れないようにする、それがsynchronizedです。

先のサンプルは、「2つのスレッドが同時にアクセスするオブジェクト」がありませんので、synchronizedの働きが今ひとつよくわからなかったのでしょう。

投稿日時 - 2012-07-10 21:51:50

お礼

早速のご回答、また、解りやすいご解説、ありがとうございました。
原因がよくわかりました。
これからも頑張ろうと思います。

投稿日時 - 2012-07-11 21:08:15

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

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

回答(1)

あなたにオススメの質問