• ベストアンサー

synchronizedを使用方法で混乱しています。

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の実装に書き換えると同期化されます。なぜでしょう?自分なりに精一杯考えましたがわかりません。分かる方、説明お願いできますでしょうか?

  • MXPX
  • お礼率16% (15/91)
  • Java
  • 回答数5
  • ありがとう数3

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

  • ベストアンサー
  • kacchann
  • ベストアンサー率58% (347/594)
回答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つが対応してる感じ。   よって同期も何もない。   */  }

MXPX
質問者

お礼

試していただいてありがとうございます。 kacchannさんの説明を読ませていただくと、なるほど!と思います。ありがとうございました。

その他の回答 (4)

  • symgt
  • ベストアンサー率56% (68/120)
回答No.5

No.1です。 現在、No.1の参考URLにアクセスできないようなので こちらに書き込ませていただきます。 Q.メソッドに付ける synchronized って何ですか? A.インスタンスをスレッド間で排他的に利用するための宣言です。  排他の範囲はメソッドではなくインスタンスであることに  注意して下さい。すなわち、 synchronized は  「メソッドを排他的に実行するための宣言」ではありません。  インスタンスが異なれば待たされずに同時に実行されますし、  synchronized を付けた別のメソッドであっても  同じインスタンスに対するものならば同時に実行されません。 ということです。 後はNo.4の方の書かれたとおりです。

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.3

Runnable継承版のソースコードも載せよう。 あと、for()ループの回数を10回でなくもっと長くすると、 状況が変わるような気がする。

MXPX
質問者

補足

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回に変更しても結果は変わりません。よろしくお願いします。

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.2

> Runnableの実装の場合、なぜ同期化できるのかお分かりでしたら、教えてもらいたいのですが? 同期化しているのではなく、単に逐次実行しているのでは? ご質問のプログラムでは、t1,t2,t3は異なるインスタンスなので、別個に排他制御されます。 つまり、事実上排他制御されないのです。

MXPX
質問者

補足

ご回答ありがとうございます。 Runnableの実装の場合: synchronizedキーワードがないと、t1,t2,t3、ランダムに表示されます。synchronizedを付けると、順番に表示します。 Threadの拡張の場合: synchronizedキーワードがないと、t1,t2,t3、ランダムに表示されます。synchronizedを付けても、ランダムに表示します。 別々のオブジェクトなんで、別個に配置制御されるのは、なんとなくですが、理解できます。 Runnableの実装の場合について、もう少し詳しい情報がほしいので、お分かりでしたら、教えてください! よろしくお願いします。

  • symgt
  • ベストアンサー率56% (68/120)
回答No.1

とりあえずpublic synchronized void ss()をstaticにしてみてください。 詳細は参考URLをご覧ください。

参考URL:
http://www.gimlay.org/~javafaq/S021.html#S021-02
MXPX
質問者

お礼

早速のご回答ありがとうございました。 Runnableの実装の場合、なぜ同期化できるのかお分かりでしたら、教えてもらいたいのですが? 参考書を見ていると、私が書いたソースのパターンで、Runnableの実装のものが多くあります。これをThreadの拡張に変更すると、同期化しなくなります。 お分かりでしたら、おしえてください。 よろしくお願いします。

関連する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(); } }

    • ベストアンサー
    • Java
  • synchronizedが解りません。

    synchronized( a ) { a.add(); } ブロック文で aオブジェクトをロックしてるはずなんですが 結果を見ると出来てないようです なぜうまくいかないんでしょうか? 教えてください。 class Test extends Thread { feet a = new feet(); public static void main( String args[] ){ for( int i = 0; i < 3; i++ ){ Test b = new Test(); b.start(); } } public void run() { synchronized( a ) { a.add(); } } } class feet{ int n, m; void add(){ n++; System.out.println( n + " " + m ); try { Thread.sleep( 1000 ); }catch( InterruptedException err ){ } m++; System.out.println( n + " " + m ); } }

    • ベストアンサー
    • Java
  • Javaのメソッドについて

    Javaの参考書を見ていて分からない点があります。 Kadaiクラスで使用したcurrentThreadメソッドは、 Thread.currentThread()と書いてもthis.currentThread()と書いても 実行結果が同じになります。 currentThreadメソッドは静的メソッドなのに、 なぜthis.currentThread()でも良いのか分かりません。 this.currentThread()も静的メソッドなのでしょうか? class SampleThread{ public static void main(String[] args){ Thread t1=new Kadai(); t1.setName("Minimum"); //スレッド名を設定 t1.setPriority(Thread.MIN_PRIORITY); //優先順位を設定 Kadai t2=new Kadai(); t2.setName("Normal"); t2.setPriority(Thread.NORM_PRIORITY); Kadai t3=new Kadai(); t3.setName("Maximum"); t3.setPriority(Thread.MAX_PRIORITY); t1.start(); //プライオリティが最低のスレッドを実行 t2.start(); //プライオリティが普通のスレッドを実行 t3.start(); //プライオリティが最優先のスレッドを実行 } } class Kadai extends Thread{ public void run(){ Thread t=this.currentThread(); //スレッド情報を取得 System.out.println("スレッド名:"+t.getName()+" プライオリティ:"+t.getPriority()); } }

    • ベストアンサー
    • Java
  • Runnableのインスタンス化について

    下記のコードについてです。 Runnableがインスタンス化されていますが、 どうしてそれが可能なのかが分かりません。 分からない点は 1.Runnableはインタフェースであるから、本来、直接インスタンス化は不可能であるはず。 2.しかし、Runnableはクラスライブラリjava.langパッケージに含まれている。 だからインスタンス化は可能なのかもしれない。 3.あるいは、下記のコードではメソッド内の無名クラスであるから、「new Runnable(){」の 部分でスーパークラスとしてのRunnableを継承したサブクラスを生成しているのかもしれない。 アドバイスをよろしくお願い致します。 public class Main{ public static void main(String[]args){ Runnable task = new Runnable(){ public void run(){ System.out.println("run"); } }; Thread thread = new Thread(task){ public synchronized void start(){ System.out.println("start"); } }; thread.start(); } }

    • ベストアンサー
    • Java
  • Threadクラスのメソッドの使用方法について

    Threadクラスのメソッドの使用方法について質問させていただきます。 Thread th = currentThread(); System.out.println("Thread Name = " + th.getName() ); というコーディングにおいて、Thread th = currentThread();は、 currentThreadメソッドがstaticなのでnewしないで使用しているのは分かるのですが、 th.getName()は、staticでないのに、newせずに使用できるのがなぜか分かりません。 どなたか宜しくご教示お願い致します。

    • ベストアンサー
    • Java
  • スレッド1とスレッド2を交互に実行するには?

    スレッド1→スレッド2→スレッド1・・・と同期を取り合いながら交互にスレッドを動かしたいのですが、Thread.getState()を用いないで実現するよい方法はないでしょうか? どうしてもデッドロックが発生しうる方法しか思いつかず困っています。 例えば以下のプログラムで1212と交互に表示させたい場合です。 以下のプログラムは当然デッドロックになりますが、やりたいことを伝えるために載せておきます。 Object obj; //スレッド間通信用のobject class Test1 extends Thread {  public void run() {   while(true) {    System.out.print("1");    synchronized (obj) {     obj.notify();//相手をnotifyして     obj.wait();//自分はwait    }   }  } } class Test2 extends Thread {  public void run() {   while(true) {    System.out.print("2");    synchronized (obj) {     obj.notify();     obj.wait();    }   }  } } new Test1().start(); new Test2().start();

    • ベストアンサー
    • Java
  • 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が先に表示されるのは仕方のないことなのでしょうか? それともプログラムがいけないのでしょうか? ご存知の方いらっしゃいましたら教えて頂けないでしょうか。 不足がありましたら仰ってください。

    • ベストアンサー
    • Java
  • コンパイルエラー(Threadオブジェクト化)

    Runnableを継承したNormalClassをThreadとしてオブジェクト化しようとしているのですが、コンパイルエラーが出現して困っています。どうすればいいでしょうか? 下記エラー参照 Main.java:1: NormalClass は abstract でなく、java.lang.Runnable 内の abstract メソッド run() をオーバーライドしません。 下記ソース class NormalClass implements Runnable{ } class Main extends Thread{ public static void main(String args[]){ test = new Thread(new NormalClass()); } }

    • ベストアンサー
    • Java
  • 別クラスのスレッドによるpaint()が上手くいきません!!

    たびたびすみません、、、今度は別のクラスに記述したpaint()をメインでスレッド起動しても描写されません…オーバーライドか何かしなければいけないらしい情報を探し当てた気がするのですが、いまいちよくわかりません。。どうすればいいのでしょうか? 下に自分で作ってみたソースの抜粋を書きます。 import java.awt.*; import java.awt.event.*; class test extends Frame { subclass sc = new subclass(); Thread th=new Thread(sc); public static void main(String args[]) { test t=new test(); } public test() { setTitle("Test"); setSize(300,200); setVisible(true); th.start(); //閉じる addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } } class subclass extends Frame implements Runnable { int i; public void run() { for(i=0;i<100;i++) { repaint(); } try { Thread.sleep(1000); } catch(InterruptedException e){} } public void paint(Graphics g) { g.drawOval(i,i,50,50); } } (EOS) どうか教えていただける方、お願いします!!

  • 交互にスレッド実行 (どうしてちゃんと動いてる?)

    http://oshiete1.goo.ne.jp/qa2968378.html で質問した者です。 2つのスレッドで1と2を交互に実行する以下のプログラム。 final Object obj1 = new Object(); //スレッド間通信用のobject final Object obj2 = new Object(); //スレッド間通信用のobject2 Thread t1 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("1");     synchronized (obj1) {      synchronized (obj2) {       obj2.notify();//相手をnotifyして      }      obj1.wait();//自分はwait     }    }   } catech (Exception e){} }; Thread t2 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("2");     synchronized (obj2) {      synchronized (obj1) {       obj1.notify();      }      obj2.wait();     }    }   } catch (Exception e){}  } }; Thread t1 = new Test1(); Thread t2 = new Test2(); t1.start(); while(t1.getState() != Thread.State.WAITING); t2.start(); が思ったように動いてはいるものの、なぜ正常に動いているかがわかりません。 t1が wait() したときはobj1のロックをもっていて、t2の synchronized (obj1){obj1.notify()} ブロックに入れず待機するはずだと思うのですが。 なぜちゃんと動いているのでしょう?

    • ベストアンサー
    • Java

専門家に質問してみよう