- - PR -
staticメソッド内の内部(自動)変数
| 投稿者 | 投稿内容 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2003-03-04 14:13
immutableとは、newした後、何をしても内部状態が変わらない ようなもののことです。たとえば、java.lang.Stringとか。 final String str = "abc"; とした場合、strに対してどんな操作をしたあとでも、str.equals("abc") のままです。だから複数スレッドで共有しても安全です。 反対に、 final StringBuffer buf = new StringBuffer("abc"); の場合、buf.append("def")とすると、buf.toString().equals("abcdef") になってしまいますよね。これはStringBufferがmutableだからです。 mutableなオブジェクトは複数スレッドで共有すると、内部状態が壊れる恐れ があります。例えば、buf.length()で長さを確認した後に、最後の1文字を deleteCharAtで削除する場合、buf.length()実行後に、他のスレッドがbuf から何文字か削除してしまうと、deleteCharAt実行時に例外になります。
一番参考になるのは、 http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html これかな。 | ||||||||
|
投稿日時: 2003-03-04 17:42
すみませんが、あと少し続けさせてください。
お恥ずかしい事に理解していた様で理解していなかったようです。 ご教授いただいた内容からわかったのですが、私の質問が的を得てない為に 自分自身で混乱を起こしていることがわかりました。つまり「自動変数」とい う広義な言葉を使用したのがまずかったようです。 staticメソッド内部のみに話を限定した場合、排他を意識しなくて良い「もの」は ・メソッド内部で割り当てられたプリミティブ型の自動変数(引数も含む) (スレッド毎別々にスタック領域に確保される) ・final且つimmutableなObject型のインスタンス (インスタンスの参照はスレッド毎別々にスタック領域に確保される。インスタンスは ヒープ領域に確保される。この場合immutableなので排他を意識する必要がない) そしてここが混乱している個所です。 ・メソッド内部でnew(インスタンス化)されたmutableなObject型のインスタンス 例えば public class StringCtrl { static public boolean chkStringRegEx( String s_In ,String s_RegEx) { StringBuffer aaa = new StringBuffer(""); aaa.append(s_In); この後なんらかの文字列操作を行う... } } このstaticメソッドであるchkStringRegExの中でnewされたaaaというmutable であるObjectのインスタンスは排他を意識する必要があるか?という所です。 ご教授いただいた内容からは推測できないのですが、結論としては排他を意識する 必要が無い様に解釈したのですが、間違っていたらご指摘を頂けますか? mutableなObjectのインスタンスは排他を意識する必要がある、さらにstaticメソッド 内部ではインスタンスの参照のみがスタックに確保されるのは理解できたのですが、 はたしてstaticメソッド内部でnewされたObjectのインスタンスは同様の参照がJVMから 返されるのか?という所です。。 同じ様な質問ですが、どうもその部分が理解できません。 | ||||||||
|
投稿日時: 2003-03-04 17:57
複数のスレッドが同時にそのメソッドを実行しても、StringBufferの インスタンスは、各スレッドごとに作るので、普通は排他の必要はあ りません。 「この後なんらかの文字列操作を行う...」でaaaを、他のスレッドから アクセス可能な場所に置く場合は必要ですが。 | ||||||||
|
投稿日時: 2003-03-04 18:12
> mutableなObjectのインスタンスは排他を意識する必要がある、さらにstatic
>メソッド内部ではインスタンスの参照のみがスタックに確保されるのは理解でき >たのですが、はたしてstaticメソッド内部でnewされたObjectのインスタンスは >同様の参照がJVMから返されるのか?という所です。。 多分,マルチスレッドプログラミングの基礎を勉強した方が良いと思います. 複数のスレッドから同時アクセスされても,排他制御が必要な場合もあれば 不要な場合もあります.複数スレッドからの同時書き込みについてさえ, 排他制御が不要な場合があります.そのほとんどはアルゴリズムに依存 するため,一概にどうだとは言えません. | ||||||||
|
投稿日時: 2003-03-04 21:59
ありがとうございます。
今度こそ理解できました。マルチスレッドプログラミングの基礎は何度か読んで 排他の必要性や危険性、デッドロックなどについては認識しているのですが、理解 しているかというと、なかなか普段マルチスレッドを使う機会がないのであいまい な部分が自分の中にたくさんあると思います。(Servletはマルチスレッドですが) 今回はどちらかというと、 newしたインスタンスなのにstaticメソッド内だからといってJVMから同様の参照 が返される等という突拍子も無い発想をした部分に問題を感じています。つまり基礎 不足でしょうか? 全体的な勉強不足ですね。。頑張らなきゃ。 | ||||||||
|
投稿日時: 2003-03-04 23:41
これは、staticメソッドでなくても、一緒です。ただ、スタック領域に置くというところまでは、VMの仕様は規定していないんじゃないかと思います。実際のところレジスタに割り当てられるケースも多いでしょうし。あと、プリミティブ型に限らず、参照変数も同じです(もちろん指している先のオブジェクトは別)。 逆に言うと、Javaの現在のメモリモデルでは、ローカル変数は、スレッドローカルなメモリ領域に置いても良いことになっているため、端的に言って、ローカル変数を複数のスレッドで共有すること自体が不可能です。なので、競合について考える必要はありません。 ローカル変数を、インナークラスで使う時にfinalを付けなければならないのも、同じ理由です。 | ||||||||
|
投稿日時: 2003-03-05 00:02
JavaVMにレジスタなんてありましたっけ? ネイティブCPUの話でしょうか。 (そもそも元の投稿の意味がどうだったかによりますが) | ||||||||
|
投稿日時: 2003-03-05 10:43
>逆に言うと、Javaの現在のメモリモデルでは、ローカル変数は、スレッドローカル
>なメモリ領域に置いても良いことになっているため、端的に言って、ローカル変数 >を複数のスレッドで共有すること自体が不可能です。なので、競合について考える >必要はありません。 多分,だいたい次の通りでいいはずです. ---- *ローカル変数とオペランドスタックはJavaフレームに含まれ,フレームは 各スレッドローカル. *インスタンスはスレッド間で共有されるヒープに置かれる. *各領域をレジスタやメモリに割り当てるのは実装依存. 多くの実装ではカレントフレームのオペランドスタック(の先頭)とローカル 変数がレジスタ,ヒープがメインメモリ(よってインスタンスもメモリ. ここでいうメモリは仮想記憶やキャッシュも含む.)ということになると 思うが,それは必須ではない.特にHotSpotVM等で最適化した場合は参照 局所性も考慮して配置する可能性があるため,その挙動を予測するのは 極めて困難. | ||||||||
