• ベストアンサー

synchronized メソッド について

http://www.stackasterisk.jp/tech/java/sjcp05_15.jsp ↑の問題の解答で ”あるスレッドが「9行目~11行目、15行目~19行目」までの処理を実行している間に、 「23行目~25行目」の処理を他のスレッドが実行することはありえるのです。” とあるのですが removeObj1メソッドとremoveObj2メソッドは synchronizedメソッドだと思うので removeObj1メソッドとremoveObj2メソッドが 同時に実行される事はないと思ったのですが synchronizedメソッドないにsynchronizedブロックが あるとブロック単位でのロックになるのでしょうか? addObj1が実行されているときに removeObj2が実行されるのはわかるのですが、 ”ArrayListのremove( )メソッドを呼ぶときに IndexOutOgBoundsExceptionが発生する可能性があるので 答えはC, Dになります。 と言うのがどうもわかりません。” 宜しくお願いします。

  • sonar
  • お礼率57% (27/47)
  • Java
  • 回答数6
  • ありがとう数5

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

  • ベストアンサー
  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.5

質問者さんは、理解できていると思います。 確かにあの図はおかしいと思います。 図の中で「synchronized(lockObj1)があるから待たされる」と言っていますが、 lockObj1はstaticではないため、「synchronized(lockObj1)があるから待たされる」ためには、 どのスレッドも同じMonitor オブジェクトを参照しなければなりません。 ということは、メソッドのsynchornizedで引っかかります。 つまり、きちんと処理されることになります。 ただ、図とは違ってきますがスレッドがそれぞれ別のMonitor オブジェクトを 参照していたとすると、待ちは一切発生しないので解答のとおり例外が発生する 可能性があります。 *lockObj1、lockObj2がstaticだったら、図の通りになったかな。

sonar
質問者

補足

ご返答ありがとうございます。 そうですか、、やっぱりあの図がおかしいですか。。 おかげ様で もやもやが取れました。(^^ すいません、今一度確認させて下さい。 > *lockObj1、lockObj2がstaticだったら、図の通りになったかな。 どのスレッドも同じMonitorオブジェクトを参照している場合 lockObj1、lockObj2がstaticだったとしても synchornizedメソッドで排他がかかるので 図のようにremoveObj1メソッドとremoveObj2メソッドが 同時に実行される事はないと考えて宜しいでしょうか?

その他の回答 (5)

  • lawson
  • ベストアンサー率44% (29/65)
回答No.6

そして、No5を補足すると ###No5##の内容の一部 >ただ、図とは違ってきますがスレッドがそれぞれ別のMonitor オブジェクトを >参照していたとすると、待ちは一切発生しないので解答のとおり例外が発生する >可能性があります。 とありますが。 具体的にどんな時に 例外が発生する可能性があるかという説明については、 私のNo2の回答の ↓の部分以降を読んでもらえればわかります。 ##No2の回答の一部 if( i < list.size() ) { という チェック処理がありますが。 ####

sonar
質問者

お礼

度々&詳細な回答をありがとうございました。 おかげ様でスレッドの理解度が深まったと 感じております。

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

>removeObj1メソッドとremoveObj2メソッドは >synchronizedメソッドだと思うので >removeObj1メソッドとremoveObj2メソッドが >同時に実行される事はないと思ったのですが 「メソッドをsynchronizedにしたのに同期化されないのはなぜ?」 という過去の質問の、 「質問文自体」と「No.5の回答」を参照。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=749910 (http://www.gimlay.org/~javafaq/S021.html 「メソッドに付ける synchronized って何ですか?」)

sonar
質問者

補足

ご返答ありがとうございます。 皆様にご教授頂いて 排他の範囲はメソッドではなくインスタンスなので インスタンスが異なれば待たされずに同時に実行できる。 、、という事で理解できそうな気がしたのですが 自分の中でどうしても【解説】の上の方の絵とマッチしません。 th1とth2でクラスMonitorを別インスタンスとしてスレッドを実行した場合、 インスタンスが異なるのでth1で実行中のメソッドもth2で実行できると 思っているのですが、それはあっていますでしょうか? 解説の絵だとthisもlockObj1,lockObj2も同じものを 指している(?)ので同一インスタンスですよね? それでいてsynchronizedメソッド(this)で排他が かかっている中のsynchronizedブロックが同時に実行できるというというのが どーもよく解りません。(^^; synchronizedメソッドでなければ自分の中では解説の絵ともマッチするのですが。。 なにか見かたがおかしいのでしょうか? なかなか難しいですが、なんとかスレッドを理解したいと考えております。 今一度、アドバイス頂ければと存じます。 宜しくお願い致します。

  • lawson
  • ベストアンサー率44% (29/65)
回答No.3

<<<<訂正>>>>> 誤) しかし、 lockObj1 をロックしている removeObj2 は上記の2つとは、 独立的、並列的に実行させることは 可能です。 正) しかし、 lockObj2 をロックしている removeObj2 は上記の2つとは、 独立的、並列的に実行させることは 可能です。 #######################3 lockObj1 → lockObj2

sonar
質問者

補足

ご返答ありがとうございます。 もうちょっとで解りそうな気がするのですが No4.の方の補足に新たに質問を書き込ませて頂きました。 もしよろしければアドバイス頂ければと思います。 宜しくお願い致します。

  • lawson
  • ベストアンサー率44% (29/65)
回答No.2

一般的にロックはリソースに対して取得するものです。 DBの行、ページ、や ファイルシステム上のファイル、 メモリ上のあるオブジェクトなど。 javaで synchronized( ブロックのなかで、 ()のなかにロックしたいオブジェクトを 与えてます。 ちなみに、 synchronized void foo() { } のような場合は void foo() { synchronized(this) { } } にほぼ、同じです。 lockObj1 と lockObj2 は ロックの制御だけのために 使われているようです。 addObj1 と removeObj1 はともに synchronized(lockObj1){ の中で listにアクセスしているので、 addObj1 と removeObj1 が同時に listにアクセスすることはありません。 しかし、 lockObj1 をロックしている removeObj2 は上記の2つとは、 独立的、並列的に実行させることは 可能です。 if( i < list.size() ) { という チェック処理がありますが。 removeObj1とremoveObj2 の両方がこのチェック処理を 通過して、ifの中にはいった時、 removeObj1が、remove(i) を実行した結果たまたま、 list.size() - 1 が i より、小さくなった時 removeObj2が remove(i) を実行すると、 IndexOutOgBoundsException が発生します。 removeObj1とremoveObj2のremove(i) を実行する順番が逆であれば、 removeObj1が remove(i) を実行したところで、 IndexOutOgBoundsException が発生します。 理解のポイントとしては、 同じリソースをロックしている もの同士(スレッド)だけが、 互いに排他制御をするという ことです。 syncronizedで、そのスレッドが どのリソースのロックを取得しようと しているかに注目してください。 以上

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

listは、クラス変数なので、複数のインスタンスから参照(共有)されます。 あるインスタンスがremoveObj1()を起動すると同時に、別のインスタンスがremoveObj2()を起動した場合に、競合の恐れがあります ――という事では。

sonar
質問者

補足

ご返答ありがとうございます。 もうちょっとで解りそうな気がするのですが No4.の方の補足に新たに質問を書き込ませて頂きました。 もしよろしければアドバイス頂ければと思います。 宜しくお願い致します。

関連する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
  • ソースコードの読み方

    ArrayList の size() メソッドの処理の仕方について、 いろいろ調べてるのですが、自分の力不足で理解ができません。 add については、 http://www.stackasterisk.jp/tech/java/collection02_02.jsp を参考にしたのですが・・・。 バイトコードでは、この size() メソッドを使うと、どのように処理してるかも知りたい所なのですが・・・。 よろしくお願いします。

    • ベストアンサー
    • Java
  • synchronizedについて

    こんにちは!質問です! javaのsynchronizedについて教えてください。 DBへの更新メソッドに、 排他制御をしようと思っているのですが、調べて自分で コーディングしました。アドバイスをお願いします! public static synchronized void update() throws SQLException{ Connection db = null; PreparedStatement objPs = null; ResultSet rs = null; StringBuffer sql = new StringBuffer(); try { Context ctx=new InitialContext(); DataSource ds=(DataSource)ctx.lookup("java:/comp/env/test/sample"); db=ds.getConnection(); sql.append("UPDATE "); sql.append("test "); sql.append("SET "); sql.append("aaa = '000', "); sql.append("bbb = '000', "); sql.append("ccc = '000' "); sql.append("WHERE dd = '0'"); objPs=db.prepareStatement(sql.toString()); objPs.executeUpdate(); } catch (SQLException e) { //エラー処理 } catch(Exception e) { //エラー処理 } finally { try { if(rs!=null) {rs.close();} if(objPs!=null){objPs.close();} if(db!=null) {db.close();} } catch(Exception e){ e.printStackTrace(); } } } クラスはpublicですが、static synchronized にしていたら、 排他制御が可能でしょうか? staticなので、インスタンス複数でも1つしか存在しないのですよね? その場合、このメソッドを呼び出しているスレッドが終了しないうちに 別のスレッドが呼び出した場合、そのスレッドはどうなるのでしょうか? 目で見て確認する方法もできれば、教えていただきたいです! また、sql発行メソッド(上記メソッド)を直接排他制御するのと、 上記メソッドの呼出元を排他制御するのと、どちらがいいとかって あるのですか? ご存知の方、よろしくお願い致しますm(_ _)m

    • ベストアンサー
    • Java
  • メソッドの処理の同期化

    いつもお世話になっています。 メソッド処理の同期化についてなのですが、 いろいろ調べてみたのですが、いまいちうまく実行できません。 ソースを考えてみたのですが、どこがどう悪いのかご指摘お願いできますでしょうか? 以下のクラスがある場合で public void Add(){ synchronized(this){ System.out.println("待機しています!"); //おそらくここら辺にwait()/notify()処理が来るきがする //同期中に行わない処理をここに記載する? } System.out.println("Addメソッド実行しました"): } public void Change(){ synchronized(this) { //おそらくここら辺にwait()/notify()処理が来るきがする //同期中に行わない処理をここに記載する? //一時停止 処理時間をずらすためループを使用 try { for(int a=0;a<3;a++){ System.out.println("a="+a); Thread.sleep(10000); } }catch (InterruptedException e) { } System.out.println("Changeメソッド完了です"); } } このとき、Add対Change/Add対Addといった形で同期化処理をしたいのですが、どうしてもうまくできません。 仮にThreadを使用して実行してみようとしたのですが、 順番に実行されてしまいます。 したいのが、 1.Addメソッド実行 2・Addメソッド実行 この場合、現状だと a=0 a=0 a=1 a=1 a=2 a=2  と表示されてしまうので、 a=0 a=1 a=2 a=0 a=1 a=2  と表示することはできるのでしょうか? 原因として、wait()/notify()が記載されていないことが影響していると思うのですが。 宜しくお願いします。

  • 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
  • ロックの取得とwaitメソッド

    インスタンスに対してwait()メソッドを実行するには、そのインスタンスのロックを取得していなくてはならないと思っています。 method2()がエラーになるのと、method3が正常に動作するのは、 インスタンスに対するロックの有無で理解できます。 ただ、下記のソースでmethod()がエラーとならない動作が理解でき ませんでした。 このメソッドだと、メソッド単位ではロックがかかっていますが、 synchronizedでないメソッドが存在すれば別スレッドからアクセスでき るので、インスタンスに対するロックを取得しているわけではないと思 います。 私の理解が間違っているのでしょうか。 class MyClass { String str = new String("a"); public synchronized void method(){ try{ wait(); } catch (Exception e) { e.printStackTrace(); } } public void method2(){ synchronized (str) { try{ wait(); }catch(Exception e){ e.printStackTrace(); } } } public void method3(){ synchronized (this) { try{ wait(); }catch(Exception e){ e.printStackTrace(); } } } } class UseMyThread1 { public static void main(String args[]) { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); MyClass mc3 = new MyClass(); //mc1.method();//ここはエラーにならない System.out.println("*********"); //mc2.method2(); //ここはエラーになる System.out.println("*********"); //mc3.method3();//ここはエラーにならない } }

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

    • ベストアンサー
    • Java
  • JSPのメソッドサイズ制限について

    JSPを初めたばかりで、基本的なこともよくわからなくてどなたかお教え願えないでしょうか Eclipseを操作しながら作成しています 今回複雑な計算処理のJSP(form文のactionで実行)で作成する予定で、メソッドが64Kバイトを超えることが想定されます JSPでは、64K バイトを超えるサイズのメソッドの生成出来ない記載と、 jspのメソッドの行数が,コメントおよび空行を含めて1000行を超える場合が発生する記載を見つけました 下記対策が有るようですが、jspではどの方法とるのがよいかですか   1.jspのスリム化には     (a)コメント、スペース、改行を減らす     (b)動的includeを使用して分割する        変数の引き渡しが必要で単純に分割出来ない     (c)beanで処理できる部分を作成        Eclipseでの作成方法の手順があるとたすかります (d)<%! function(){} %>別メソッドを作成        この方法は正しいかわかりません   2.jspでなくてservletで作成する        

    • ベストアンサー
    • Java
  • wait中にinterruptを呼ばれたスレッドの振る舞いについて

    はじめまして。javaの初心者です。 どうしてもわからないことがあります。 例えば、以下のコードで、 class Foo { public synchronized void foo() { while(条件) { try { this.wait(); } catch(InterruptedException ex)    {     処理    } } } } wait中であったスレッドは、他のスレッドによって interrupt()メソッドを実行されたときは、Fooの ロックを取得してからcatch節を実行すると思うのですが、もし、以下のコードの場合は、 class Foo { public synchronized void foo() throws InterruptedException { while(条件) { this.wait(); } } } wait中であったスレッドは、他のスレッドによって interrupt()を実行されたときにすぐにInterrupted Exceptionをスローするのか、それとも Fooクラスのロックを取得してからInterruptedExceptionをスローするのかどちらなのか がわかりません。どうか教えてください。よろしく お願いします。

    • ベストアンサー
    • Java
  • スレッドの状態遷移について。。。

    Javaの本を買って読んでいます。 その中の「スレッド」のカテゴリーの「状態遷移」のところの「synchronized」の部分に、こう書かれています。 -------------------------- ・・・・・・ なお、sleepメソッドでスリープ状態(実行不可能状態)になったスレッドはロックを保持したまま開放しません。 そのため、ロックを取得できないで待たされるスレッドも実行不可能状態へ移行させられます。 -------------------------- これは、Synchronized指定されたメソッド(同期メソッド)の部分で出てきた文章でして、 私は、こう解釈しました。 → 例えば、同じオブジェクトの参照を引数とするスレッドが3つあり、その中の1つが『実行中』状態にある(仮に t1 とする)として(つまり残り2つ( t2 t3 )は『実行可能状態(プール)』にある。)、 実行中の t1 がsleep()メソッドで『実行不可能状態』になった場合、 『実行可能状態』にあった、t2 t3 も『実行不可能状態』へ移行する事になる。 間違っていますか? もし、この解釈が正しければ、こうなりますよね? t1・・・・・・・『実行中』 → 『実行不可能状態』 t2 t3・・・『実行可能状態』 → 『実行不可能状態』 ところが、状態遷移の5つの状態の図を見ると、 『実行可能状態』 から 『実行不可能状態』 へは、矢印→が書かれておりません。(逆向きの矢印がありますが。) どういう意味でしょうか。 java初心者ですが、 解りやすく教えて頂けると助かります。 宜しくお願い致します。

    • ベストアンサー
    • Java

専門家に質問してみよう