JAVAを独学で勉強しております。synchronizedをインスタンスメソッドに使用したのですが、同期化できません。いくら考えてもわからなかったので、質問しました。ソースを記入します。
class Test extends Thread{
public void run(){
ss();
}
public synchronized void ss(){
for(int x=1;x<=10;x++){
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args){
Test t1 =new Test();
Test t2 =new Test();
Test t3 =new Test();
t1.start();
t2.start();
t3.start();
}
}
実行すると、同期化されてなく、ランダムに表示されます。違うオブジェクトで参照しているから、ロックかけても意味がないのかなーとも思っていますが、
Threadの拡張じゃなく、Runnableの実装に書き換えると同期化されます。なぜでしょう?自分なりに精一杯考えましたがわかりません。分かる方、説明お願いできますでしょうか?
No.1
- 回答日時:
とりあえずpublic synchronized void ss()をstaticにしてみてください。
詳細は参考URLをご覧ください。
参考URL:http://www.gimlay.org/~javafaq/S021.html#S021-02
早速のご回答ありがとうございました。
Runnableの実装の場合、なぜ同期化できるのかお分かりでしたら、教えてもらいたいのですが?
参考書を見ていると、私が書いたソースのパターンで、Runnableの実装のものが多くあります。これをThreadの拡張に変更すると、同期化しなくなります。
お分かりでしたら、おしえてください。
よろしくお願いします。
No.2
- 回答日時:
> Runnableの実装の場合、なぜ同期化できるのかお分かりでしたら、教えてもらいたいのですが?
同期化しているのではなく、単に逐次実行しているのでは?
ご質問のプログラムでは、t1,t2,t3は異なるインスタンスなので、別個に排他制御されます。
つまり、事実上排他制御されないのです。
この回答への補足
ご回答ありがとうございます。
Runnableの実装の場合:
synchronizedキーワードがないと、t1,t2,t3、ランダムに表示されます。synchronizedを付けると、順番に表示します。
Threadの拡張の場合:
synchronizedキーワードがないと、t1,t2,t3、ランダムに表示されます。synchronizedを付けても、ランダムに表示します。
別々のオブジェクトなんで、別個に配置制御されるのは、なんとなくですが、理解できます。
Runnableの実装の場合について、もう少し詳しい情報がほしいので、お分かりでしたら、教えてください!
よろしくお願いします。
No.3
- 回答日時:
Runnable継承版のソースコードも載せよう。
あと、for()ループの回数を10回でなくもっと長くすると、
状況が変わるような気がする。
この回答への補足
Runnableの方のソースです。
Test t1 =new Test();
Test t2 =new Test();
Test t3 =new Test();
上記のソースを下記に変更です。
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
Thread t3 = new Thread(test);
それと、Threadの拡張から、Runnableの実装に変更します。分かりにくいかもしれませんが、アドバイスお願いします!ループの件ですが、100回に変更しても結果は変わりません。よろしくお願いします。
No.4ベストアンサー
- 回答日時:
No.3です。
そのRunnable継承版のソースコードだと、
たしかに同期化される…。
MXPXさんの書いた
Thread継承版のソースコードと
Runnable継承版のソースコードとでは、
「別物の」ソースコードになっているので、
この書き方のままでは両者を比較できない。
(※ソースコードの書き方の違いであって、
Thread継承とRunnable継承の違いではない)
/**
*Runnable継承版のmain()
*/
public static void main(String[] args){
Test test = new Test();//Testのインスタンス作成(唯一)
Thread t1 = new Thread(test);//第1スレッド作成
Thread t2 = new Thread(test);//第2スレッド作成
Thread t3 = new Thread(test);//第3スレッド作成
t1.start();//第1スレッド開始
t2.start();//第2スレッド開始
t3.start();//第3スレッド開始
/*この時点で、3つのスレッドが存在し、
そのいずれもが「唯一のTestインスタンスのrun()メソッド」
を定期的に呼び出すことになる
(つまり3つのスレッドが競って1つのインスタンスのメソッドを呼び出す)。
いいかえると
「スレッド3つに、呼ばれるほう1つ」。
ってことで、その「呼ばれる」唯一のメソッドにsynchronized
を付ければ当然、
そのメソッド呼び出しは同期化される。
*/
}
/**
Thread継承版のmain()
*/
public static void main(String[] args){
Test t1 = new Test();//第1Testインスタンス(かつ第1スレッド)作成
Test t2 = new Test();//第2Testインスタンス(かつ第2スレッド)作成
Test t3 = new Test();//第3Testインスタンス(かつ第3スレッド)作成
t1.start();//第1スレッド開始
t2.start();//第2スレッド開始
t3.start();//第3スレッド開始
/*この時点で、3つのスレッドが存在し、
それぞれが「別々のTestインスタンスのrun()メソッド」
を定期的に呼び出すことになる
(つまり3つのスレッドが競って1つのインスタンスの
メソッドを呼び出すわけではない)。
いいかえると
「スレッド3つに、呼ばれるほうも3つ」。
呼ばれる側のメソッド1つに、
(いわば専属の)実行用スレッド1つが対応してる感じ。
よって同期も何もない。
*/
}
試していただいてありがとうございます。
kacchannさんの説明を読ませていただくと、なるほど!と思います。ありがとうございました。
No.5
- 回答日時:
No.1です。
現在、No.1の参考URLにアクセスできないようなので
こちらに書き込ませていただきます。
Q.メソッドに付ける synchronized って何ですか?
A.インスタンスをスレッド間で排他的に利用するための宣言です。
排他の範囲はメソッドではなくインスタンスであることに
注意して下さい。すなわち、 synchronized は
「メソッドを排他的に実行するための宣言」ではありません。
インスタンスが異なれば待たされずに同時に実行されますし、
synchronized を付けた別のメソッドであっても
同じインスタンスに対するものならば同時に実行されません。
ということです。
後はNo.4の方の書かれたとおりです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java final 1 2022/06/10 22:49
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# 質問です 下記のコードを分かりやすく解説お願いします 初心者です #include ‹stdio.h 3 2022/05/26 22:03
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- C言語・C++・C# 大量のデータを読み込んで表示する速度を改善したい 8 2023/05/07 13:29
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Java 直し方について教えて頂きたいです。 4 2022/08/13 02:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
インスタンス参照でアクセスで...
-
変数の参照でエラーが出てしま...
-
生成したインスタンスを削除す...
-
複数の変数を宣言する時、同時...
-
VB.NET getとsetの概念がわかり...
-
C#「オブジェクト参照が必要で...
-
マルチスレッドでのインスタン...
-
文字列を日付に変換でParseExce...
-
C#において、同じインスタンス...
-
private static という変数の修飾
-
VC#での24ビットbmp形式での保...
-
「インスタンス」の意味をわか...
-
SQLを連続発行する時の正しい(?...
-
抽象クラスのインスタンス生成...
-
MDIでフォームがアクティブにな...
-
サーブレットでレスポンスが返...
-
プログラミング、シューティン...
-
日数計算について
-
変数名の付け方
-
インスタンス生成で、○○.xxx();...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
変数名の付け方
-
インスタンス参照でアクセスで...
-
複数の変数を宣言する時、同時...
-
private static という変数の修飾
-
VB.NET getとsetの概念がわかり...
-
C#において、同じインスタンス...
-
生成したインスタンスを削除す...
-
C# インスタンスの破棄
-
newしないインスタンス?実体化...
-
SQLを連続発行する時の正しい(?...
-
「インスタンス」の意味をわか...
-
文字列を日付に変換でParseExce...
-
変数の参照でエラーが出てしま...
-
フォームの存在をチェックする方法
-
javaのクラスの作り方、エラー...
-
オブジェクト参照がオブジェク...
-
String a = "a"; と String b =...
-
エクセル(複数インスタンス)...
-
C#「オブジェクト参照が必要で...
-
他のファイルの変数参照
おすすめ情報