• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:コンストラクタの処理と参照が返るのはどちらが先?)

コンストラクタの処理と参照が返るのはどちらが先?

このQ&Aのポイント
  • コンストラクタの処理と参照が返るのはどちらが先?この質問では、コンストラクタが起動する前に参照が返される可能性がある問題について検討されています。
  • 具体的には、コンストラクタが終了する前に別のスレッドで参照が行われてしまい、未初期化のシングルトンへの参照が返される可能性がある問題です。
  • 質問者は自身の環境でデバッガを用いて確認しましたが、コンストラクタが終了するまでは参照がnullであることが確認できました。しかしこの問題はVMのバージョンや再現性の問題かもしれません。

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

  • ベストアンサー
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

# 有名なネタですよね…。 Javaの場合(C++等ではまた別の話)、VM仕様上out-of-order書き込みが許されるので、 同期がとれる「保証がない」(常に成立するとは限らない)と。 「常にそうなる」というものではなくて、JavaVMの仕様上(≒理論上)、 環境などにより、そうなることがありうるというものなので、 デバッガでとめてみても、多くの場合は質問者さんが確認したような結果になると思いますよ。 # 現実には絶対に現象がでない環境もあれば、出る可能性がある環境もありえる。 # そもそも、他言語などの一般的なロジックとしてはDouble-lockは有効ですし。 そして、そうなってもいいことが許されている以上、 もしもソースがそうならないことを前提に書かれていて、なってしまった場合、 そのソースのバグであって、VMに文句を言える筋ではないので、 そういう書き方は(Javaでは)好ましくないと。

thamansa
質問者

お礼

特定のVMの実装上は問題なくても、VMの仕様が保証していないので、 この件のダブルチェックパターンは使うべきでないということだったんですね。 よくわかりました。ありがとうございます。 しかし、このような罠のような仕様があると、普段書いている foo = new Foo(); が、本当に安全なのか自身がなくなっちゃいます。何を信じてよいものかという気になります。 はぁ・・・(ため息)

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

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

#3です。捕捉。 --- 読んでみて、わかりやすかった資料: ・『デザインパターン入門 マルチスレッド編』増補改訂版 http://www.hyuki.com/dp/dp2.html の[付録B] (「Java言語仕様」の"メモリモデル"の改訂を受けて、 この本も"旧版"の該当箇所を改訂している) ・http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html の 「What is a memory model, anyway? 」 「Do other languages, like C++, have a memory model?」 ・あと「Java言語仕様 第3版」の17章にも 「reordering」の話が、わりとていねいに書かれているみたいです。 ちゃんと読んでませんが・・・。 (「Java言語仕様 第2版」とだいぶ様子が違うかんじ)

全文を見る
すると、全ての回答が全文表示されます。
  • kacchann
  • ベストアンサー率58% (347/594)
回答No.3

詳しくないので解説できませんが・・・ ↓わかりやすそうな説明。 http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering (「as-if-serial semantics」というのは、 たぶん 「ある命令群があって、 それがシングルスレッド上で実行されたと"仮定した"場合、 その"結果"が変わらないのであれば、 その命令群に対し、 どんな「順序変更(reordering)」をしても構わない」 という意味・・・のような気がスルンですが)

全文を見る
すると、全ての回答が全文表示されます。
  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.1

マルチスレッドで動いたときの話ですね。 あまり自信はありませんが、、、 スレッド1とスレッド2がほぼ同時(スレッド2が若干遅く)に実行した場合で、 1.スレッド1が instance = new Singleton(); を実行 2.スレッド2が instance = new Singleton(); を実行開始 3.スレッド1がreturnで抜ける 4.スレッド2が instance = new Singleton(); を実行終了 というタイミングがあるということだと思います(たぶん)。

thamansa
質問者

補足

引用が足りなかったようですみません。 スレッドセーフなシングルトンの実装手段として、次のDouble-checkedはダメだ という記事なのですが、 | Listing 4. Double-checked locking example | | public static Singleton getInstance() | { |  if (instance == null)       //0 |  { |   synchronized(Singleton.class) { //1 |    if (instance == null) //2 |     instance = new Singleton(); //3 |   } |  } |  return instance; | } //3の箇所で、instanceに値が入るのは、コンストラクタが起動する直前なので、コンストラクタがオブジェクトの初期化を完了しないうちに、別のスレッドが//0の位置に来ると、instance == null が偽となって、初期化の終わっていないオブジェクトを返してしまう、 という解釈なのですが、 Eclipseでコンストラクタの中にブレークポイントを設定し、 別のスレッドで(Runnableで動かしてます)は//0のところでとめて評価内容を見てみると、記事の説明とは違って、instanceはまだnullでした。 記事の書かれたときとVMの実装がちがうのか、私の解釈が間違っているのか、再現方法に問題があるのか、皆さんにも試していただきたくて質問いたしました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C++ シングルトン マルチスレッド

    標準C++でシングルトンを実装したいのですが。 class Singleton{ public: static Singleton* getInstance(){ if (_instance == NULL){ //スレッドAがこの時点で、スレッドBがNULLチェックすると破綻する _instance = new Singleton(); } return _instance; } private: Singleton(); static Singleton* _instance; }; マルチスレッドになると上記のパターンで破綻するといわれどうしたものかと考えております。 static Singleton* _instance = new Singleton(); と出来れば解決なのですが 「static const int データメンバ以外をクラス内で初期化することはできません」 とのことでそれもできず。 どのようにすればよいでしょうか。

  • デザパタ シングルトンクラスの実態宣言の場所について

    //-----singleton.h---------------------------------------- // Copyright(C) 2003 Yoshinori Oota All rights reserved. #ifndef SINGLTON #define SINGLTON #include <iostream> #include <string> using namespace std; class Singleton { public: static Singleton* Instance(); static void Destroy(); void nextState(); void printState() const; private: Singleton(); ~Singleton(); static Singleton* theInstance; string value_; }; //ここじゃだめなの? //Singleton* Singleton::theInstance = NULL; #endif //------------------------------------------------------- //-----singleton.cpp--------------------------------------- #include"singleton.h" Singleton* Singleton::theInstance = NULL; Singleton::Singleton() : value_("initial state") { } Singleton::~Singleton() { } Singleton* Singleton::Instance() { if (theInstance == NULL) { theInstance = new Singleton(); } return theInstance; } void Singleton::Destroy() { if (theInstance != NULL) { delete theInstance; theInstance = NULL; } } void Singleton::nextState() { if (value_ == "initial state") { value_ = "second state"; } else if (value_ == "second state") { value_ = "third state"; } else if (value_ == "third state") { value_ = "initial state"; } } void Singleton::printState() const { cout << value_ << endl; } //------------------------------------------------------ //----main.cpp------------------------------------------- #include"singleton.h" int main() { Singleton* theSingleton = Singleton::Instance(); theSingleton->printState(); theSingleton->nextState(); theSingleton->printState(); //デストラクタも隠蔽することにより、2重deleteを防げる Singleton::Destroy(); } //-------------------------------------------------------- デザパタのシングルトンを勉強していたのですが、 実態の宣言(Singleton* Singleton::theInstance = NULL;)はヘッダファイル内だとなぜだめなのでしょうか? さらにprivate修飾がついてるのに、なぜNULLにセットできるでしょう。 参照HP http://www002.upp.sonet.ne.jp/ys_oota/mdp/Singleton/index.htm

  • シングルトン内で使用したオブジェクトのGC

    基本的な質問で恐縮ですがGCについて教えてください。 例えば、シングルトンインスタンス内のhogemethodメソッドにてHashMapのインスタンスを 生成・使用した場合(以下の質問に続く)、 【質問】 hogemethodメソッドが終わればHashMapのインスタンスはスコープを外れるので、hogeMap = null;などしなくてもGC対象となり、そのうちGCされるのでしょうか?いやいや、hogeMap = null; することによりGC対象となり、そのうちGCされるのでしょうか?それとも、nullセットしようがしまいが、シングルトンのインスタンスが存在し続ける限りGC対象とはなってもGCされることは無いのでしょうか? package hoge; public class MySingleton {  private static MySingleton instance = new MySingleton();  private MySingleton() {}  public static MySingleton getInstance() {   return instance;  }  public void hogemethod() {   HashMap hogeMap = new HashMap();   hogeMap .put("りんご", "apple");   hogeMap .put("ぶどう", "grapes");     :   hogeMap = null; ←★hogeMap をGC対象にするためにはnull代入は必要なのか?  } } よろしくお願いします。

    • ベストアンサー
    • Java
  • NULLが返ってこない…。

    原因がわからないため質問をさせて頂きます。 <%-- JSP <input type="text" name="name"> //名前 String name = request.getParameter("name"); Data data = new Data(); //コンストラクタをnew data.setName(name); --%> <%-- class(Bean) private String n = null; public void setName(String name){ if(name != null){ n = name; }else{ n = null; } public String getName(){ if(name != null){ return name; }else{ return name; } } --%> 値をgetParameter()メソッドで取得をして 値をsetName(name);でセットをしています。 セットした側でもし値があるのであれば その値を変数に格納。 もし値がなければnullを変数に格納しています。 しかし System.out.println(data.getName().equals("");//true System.out.println(data.getName().equals(null);//false; となりnullを返してくれません…。 このコードに何を足したらnullを返してくれるのか わかりません。 わかる方がいらっしゃいましたらよろしくお願い致します。

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

    はじめまして。 以下のようなプログラムで、new FileWriter("test1.txt")の【test1.txt】が最終的にどの親クラスのコンストラクタ(メソッド?)に渡されて処理されるのかがわかりません。 new演算子で FileWriterオブジェクトを作成した際に、importした親クラスのFileWriterクラスにあるコンストラクタが呼び出されるのだろうとは思っています。 そこで、JavaのAPIのサイトにて、クラス FileWriterの説明(http://docs.oracle.com/javase/jp/6/api/)を読みましたが、コンストラクタが複数紹介されており、下記のプログラムに当てはまるものがどれか分かりませんでした。 また、クラス FileWriterの説明ページのコンストラクタの概要にあるpublic FileWriter(File file)というコンストラクタの場合、引数リストのFileにもリンクがあり、Fileのリンク先のページであるクラス Fileの説明(http://docs.oracle.com/javase/jp/6/api/)を読みましたが、結局test1.txtがどのクラスのコンストラクタ(メソッド?)でどのように処理されているのかが分かりません。 どうかご教示いただきたく、よろしくお願い致します。 import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Sample7 { public static void main(String[] args){ PrintWriter pw = null; try{ pw = new PrintWriter (new BufferedWriter(new FileWriter("test1.txt"))); pw.println("Hello!"); pw.println("GoodBye"); System.out.println("ファイルに書き込みました。"); }catch(IOException e){ System.out.println("入出力エラーです。"); }finally{ if(pw != null){ pw.close(); } } } }

    • ベストアンサー
    • Java
  • JAVAに関する意味不明なerror fileが

    一部を後記してあるエラーmsgの、 下記名前のfileがdesktopに生じるようになりました。 ご説明と、出ぬようにする方法をお教えください。 「hs_err_pid2772」 **************************** # # A fatal error has been detected by the Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d7fdd89, pid=2772, tid=3184 # # JRE version: 6.0_29-b11 # Java VM: Java HotSpot(TM) Client VM (20.4-b02 mixed mode, sharing windows-x86 ) # Problematic frame: # V [jvm.dll+0xdd89] # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp # --------------- T H R E A D --------------- Current thread (0x02c8c800): VMThread [stack: 0x02d70000,0x02dc0000] [id=3184] siginfo: ExceptionCode=0xc0000005, reading address 0x00000012 Registers: EAX=0x0000000e, EBX=0x32e89af8, ECX=0x2295960c, EDX=0x0000000e ESP=0x02dbf92c, EBP=0x02dbf930, ESI=0x2295960c, EDI=0x0084bbc8 EIP=0x6d7fdd89, EFLAGS=0x00010202 Top of Stack: (sp=0x02dbf92c) 0x02dbf92c: 2295960c 02dbf950 6d84a91f 0000000e 0x02dbf93c: 02dbfa80 23475b5c 32e89af8 0084bbc8 0x02dbf94c: 0000000a 02dbf970 6d86ace1 2295960c 0x02dbf95c: 234942c0 23475b50 02dbfa80 32e89b00 0x02dbf96c: 32e89960 02dbf990 6d857a48 23475b50 0x02dbf97c: 23475b60 0084bbc8 02dbfa80 00000000 0x02dbf98c: 008483b0 02dbf9a4 6d84968d 02dbfa80 0x02dbf99c: 0084dd40 00000000 02dbf9b8 6d84ecda Instructions: (pc=0x6d7fdd89) 0x6d7fdd69: 30 8b c1 c1 e9 02 f3 a5 8b c8 83 e1 03 f3 a4 5f 0x6d7fdd79: 5e 5d c2 04 00 cc cc 55 8b ec 8b 55 08 56 8b f1 0x6d7fdd89: 8b 4a 04 8b c1 c1 f8 02 85 c9 89 4d 08 7f 35 7d 0x6d7fdd99: 2b 8b 76 08 8b 45 08 8b 15 24 0c a6 6d 83 e1 3f Register to memory mapping: EAX=0x0000000e is an unknown value EBX=0x32e89af8 is an oop {instance class} - klass: {other class} ECX=0x2295960c is an oop [I - klass: {type array int} - length: 6 EDX=0x0000000e is an unknown value ESP=0x02dbf92c is an unknown value EBP=0x02dbf930 is an unknown value ESI=0x2295960c is an oop [I - klass: {type array int} - length: 6 EDI=0x0084bbc8 is an unknown value Stack: [0x02d70000,0x02dc0000], sp=0x02dbf92c, free space=318k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [jvm.dll+0xdd89] V [jvm.dll+0x5a91f] V [jvm.dll+0x7ace1] V [jvm.dll+0x67a48] V [jvm.dll+0x5968d] V [jvm.dll+0x5ecda] V [jvm.dll+0x59ac7] V [jvm.dll+0x5fcf8] V [jvm.dll+0x5799b] V [jvm.dll+0x13afd7] V [jvm.dll+0x11d8c3] V [jvm.dll+0x11cb9e] V [jvm.dll+0x11cec0] V [jvm.dll+0x11d2c2] V [jvm.dll+0x140fec] C [msvcr71.dll+0x9565] endthreadex+0xa0 C [kernel32.dll+0xb729] GetModuleFileNameA+0x1ba VM_Operation (0x0767f7c8): GenCollectForAllocation, mode: safepoint, requested by thread 0x03ea0800 --------------- P R O C E S S --------------- Java Threads: ( => current thread ) 0x03ea0800 JavaThread "RateCaptorThread" [_thread_blocked, id=1940, stack(0x07630000,0x07680000)] 0x02d30000 JavaThread "pool-2-thread-1" [_thread_blocked, id=2384, stack(0x075e0000,0x07630000)] 0x03e9b800 JavaThread "Account" [_thread_blocked, id=3464, stack(0x07590000,0x075e0000)] 0x03e9a000 JavaThread "Order" [_thread_blocked, id=1268, stack(0x07540000,0x07590000)] 0x02d66400 JavaThread "Position" [_thread_blocked, id=1972, stack(0x074f0000,0x07540000)] 0x02d65400 JavaThread "Thread-20" [_thread_blocked, id=836, stack(0x074a0000,0x074f0000)] 0x02d62400 JavaThread "Thread-19" [_thread_blocked, id=3316, stack(0x07450000,0x074a0000)] 0x04040800 JavaThread "UFoQuoteModule-PostOffice" [_thread_blocked, id=3936, stack(0x07400000,0x07450000)] 0x0363bc00 JavaThread "WpclManager" [_thread_blocked, id=1960, stack(0x07360000,0x073b0000)] 0x0363a000 JavaThread "WpclResponseReceiveManager" [_thread_in_native, id=2304, stack(0x07310000,0x07360000)] 0x03e1a000 JavaThread "WpclRequestSendManager" [_thread_blocked, id=2348, stack(0x072c0000,0x07310000)] 0x02d2e400 JavaThread "Thread-15" [_thread_blocked, id=3760, stack(0x07270000,0x072c0000)] 0x03f16400 JavaThread "UFoChartModule-PostOffice" [_thread_

  • コンストラクタの super() で処理が止まります。

    いつもお世話になってます。 eclipse & Visual Editor にて開発しております。 JFrame を継承したクラスを作成したのですが コンストラクタにて super() を呼び出したときに 処理が止まる?ようになってしまいます。 NoSuchMethodException(Throwable).<init>(String)行: 195 上記、タブが追加されて、 ----- ソースが見つかりませんでした。 ソース・ルックアップ・パスの編集 ← ボタン ----- が表示されている状態です。 解決策が分かりません。 どの辺りから調べれば良いのでしょうか?

    • ベストアンサー
    • Java
  • スクリプトエラーとは…?

    SonicAtageVを利用中 このページのスクリプトでエラーが発生しました ライン:26 文字:4 エラー:プロパティ‘style’の値を取得できません。オブジェクトはNullまたは未定義です。 コード:0 URL:http://cnt01.labelgate.com/mora/xml/rank/dz_ranking_jacket_i.html このページのスクリプトを実行し続けますか? と出ます。 「はい」を選択しても「いいえ」を選択しても 何も起きません。 すぐに同じエラーが2,3回表示されてしばらくでなくなります。 何が原因で、どのように対処したらいいのでしょうか。

  • リフレクション

    Webアプリ上でリフレクションにてとあるクラスのメソッドを実行するサンプルを作成して 見たのですがうまく動きませんでした。最後のmethod.invoke()の処理にてExceptionが発生し、 java.lang.IllegalArgumentException: object is not an instance of declaring class と表示されてしまいます。 作成したサンプルは下記なのですがどこが原因かお分かりになりますでしょうか。 try { Class cls = Class.forName("dao.TestDao"); // 引数の型をセット Constructor constructor = cls.getDeclaredConstructor(HttpSession.class); constructor.setAccessible(true); // 引数を渡してオブジェクトを生成 Object obj = constructor.newInstance(session); Method method = cls.getDeclaredMethod("getDataDao", int.class); method.setAccessible(true); Object result = method.invoke(cls, new Integer(100)); } catch (Exception e) { e.printStackTrace(); } // このクラスのgetDataDao()をリフレクションにて実行 public class TestDao { HttpSession session = null; public TestDao(HttpSession session) { this.session = session; } public List<String> getDataDao(int iNo) { List<String> list = new ArrayList<String>(); list.add((String)session.getAttribute("1")); list.add((String)session.getAttribute("2")); list.add((String)session.getAttribute("3")); list.add((String)session.getAttribute("4")); list.add((String)session.getAttribute("5")); return list; } }

    • ベストアンサー
    • Java
  • クラスモジュールを使ったレコードセットの取得

    次のページにてクラスモジュールを使ったレコードセット の取得についてかかれています。 http://www.happy2-island.com/access/gogo04/capter01400.shtml http://www.happy2-island.com/access/gogo04/capter01500.shtml http://www.happy2-island.com/access/gogo04/capter01600.shtml ここでは単一レコードが前提になっているようですが、複数 レコードをループしながら値を取得する場合はどうすればいいの でしょうか?