• ベストアンサー

staticのメリット、デメリット

こんばんは。 staticについて、だんだんわからなくなってきました・・・。 例えばあるクラスの変数で、 static int i = 10; とあった場合、参照クラスからiの値を見ると、必ず10ですよね? static修飾子がついているメソッドの場合、挙動はどうなるのでしょう? staticなメソッドはインスタンス化しなくても呼び出せる。 つまり、メモリ上に1箇所しか存在しないので、同時にアクセスされた場合(synchronizedしていない場合)はどうなるのかがわかりません・・・。 メソッドには引数が存在し、returnがStringやintなどの場合です。 returnは保証(参照側にとって望む値と言う意味で)されるのでしょうか? インスタンス化をしない事によって、パフォーマンスが向上するのでしょうけれど、いまいちメリットがわかりません・・・。 public、privateにかかわらず、メソッドをstatic修飾するメリットを教えてください。 同時にデメリットもお願いします。 以上、下手くそな文章ですみません・・・。 (^^ゞ

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

  • ベストアンサー
回答No.8

No.7にちょっと、訂正です。。。 >>DBのコネクションはクラス変数で、 >>外部のクラスをnewしております。 >対象のメソッド内でnewして、その参照をローカル変数 >に代入しているのならば、他のスレッドにその参照 >を渡さない限り(自分からしかアクセスできないの >だから)大丈夫です。 生成したインスタンス(コネクション)の参照をクラス変数に格納しているんですね。 早とちりでした。ごめんなさい。 で、この場合はこのクラス変数の参照先を変えられたくないのに他のスレッドにも変える手段を公開している場合や、このクラス変数の参照先のインスタンスがスレッドセーフでないのに同時にアクセスできる場合は問題ですね。 コネクションの生成だけが目的ならそのままリターンするでしょうし、このメソッド内でこの後使用する為ならローカル変数で十分でしょうし・・ 生成したコネクションをクラス変数に格納する目的はどのようなものなのでしょうか?

taka451213
質問者

お礼

こんにちは。 何度もありがとうございます。 >>生成したコネクションをクラス変数に格納する目的はどのようなものなのでしょうか? 私もわからないんです・・・。 そのソースを見た瞬間、危ないんじゃないかな?って思ったもので。 今回の質問の次第となりました。 クラス変数をローカル変数に変更して、各メソッドの引数に与えて持ち回るように変更してみました。 今回のプロジェクトは途中参加(コーディングはほぼ完了していた)ですので、あまり把握できていません。 ただ全体を見る限りでは、かなりやばそうです・・・(スレッドセーフ)。 このあたりで締め切ります。 後は自分で勉強して、頑張ってみます。 たくさん回答をいただきまして、ありがとうございました。 この場を借りて、皆様にお礼申し上げます。 また質問するかも知れませんが、よろしくお願いします。 皆さんにポイントをつけたいのですができませんので・・・(このシステム、変更して欲しいです)。 つかなかった方ごめんなさい。 優劣つけられません。 本当に、ありがとうございました。 (^^ゞ

その他の回答 (7)

回答No.7

こんにちは。 うーん、単純に各変数がどのようにメモリ領域に展開されるかを理解すれば、なにが安全で、何が危険なのか、 理解されると思うのですけれどね。 とりあえず Hotspot VMではこんな感じですか。 ローカル変数 スタック領域に展開されます。スタック領域はスレッド毎に割り当てられます。 インスタンス変数 ヒープ領域(正確にはNew Generation領域/Old Generation領域)に、インスタンス毎に確保されます。 クラス変数 ヒープ領域(正確にはpermanent generation領域・・この領域はJVMが動的にクラスをロードするのでヒープ上ですが、役割的にはC/C++におけるコード領域や恒久変数領域と同じです)に、クラス毎に確保されます。 >このような複雑で時間がかかる処理を実行する >メソッドの場合は大丈夫なのでしょうか? ですので、マルチスレッドで対象のメソッドを実行し、処理時間がかかったとしても、ローカル変数を参照している分にはスレッドセーフです。 >DBのコネクションはクラス変数で、 >外部のクラスをnewしております。 対象のメソッド内でnewして、その参照をローカル変数に代入しているのならば、他のスレッドにその参照を渡さない限り(自分からしかアクセスできないのだから)大丈夫です。 >ここで取得したコネクションクラスをまた別クラスの >引数に渡したり・・・。 やっぱり、PecoPlusさんがおっしゃっているように、スレッドとインスタンスがごっちゃになっていませんか? 問題になるのは、クラス変数への(更新を伴う)アクセスや複数のスレッドが参照しているインスタンスのインスタンス変数への(更新を伴う)アクセスです。 これを複数のスレッドが行えば、期待されている結果が得られない可能性があるでしょう。 同一スレッド内でだけ使用するインスタンスに渡しても他のスレッドからアクセス出来ないですよね? あと、staticについては、このように機能的な面でのメリット/デメリットを考えるのも必要でしょうが、オブジェクト指向での概念的な面から理解されてみると、どのような振る舞いや属性に使用するものか見えてくるかもしれませんね。

taka451213
質問者

お礼

こんにちは。 回答ありがとうございます。 >>やっぱり、PecoPlusさんがおっしゃっているように、スレッドとインスタンスがごっちゃになっていませんか? なってます・・・。 >>単純に各変数がどのようにメモリ領域に展開されるかを理解すれば、 なるほど・・・、納得です。 このあたり、自分なりにもっと調べて勉強してみます。 スレッドセーフの概念って、難しいですね・・・。 正直、ついて行けそうにないです。 頑張ってみます。 (^^ゞ

  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.6

 こんにちは。 >public static String test(String string, int len){ >return string.substring(len); >}  これは、スレッドセーフだと思います。  Stringクラスは不変オブジェクトなので、複数のスレッドが同時にアクセスしても、おかしくなりようがないと思います。  あと、例えば public static int calc(int n) {   int sum = 0;   for (int i = 1; i <= n; i++)     sum += i;   return sum; }  こういうのもローカル変数しか使ってないので、スレッドセーフのはずです。  複数のスレッドがメソッドに入っても、ローカル変数は、それぞれのスレッドに割り当てられるので、各スレッドが見ているローカル変数 sum や i は、別物です。  だから、干渉を起こしません。  これが、 static int n; public static int calc() {   int sum = 0;   for (int i = 1; i <= n; i++)     sum += i;   return sum; }  クラス変数を見るように作ってあると、クラスをロックして同期化しないとおかしなことになります。

taka451213
質問者

お礼

こんばんは。 回答ありがとうございます。 やっと理解できたような気がします・・・。 もう少しだけお願いします。 下記のような場合はどうなのでしょう? public static 戻り値 test(引数){ この中で別のクラス(staticではない)などを呼び出して実行している。 データベースがらみの処理で、結構時間がかかる・・・。 } このような複雑で時間がかかる処理を実行するメソッドの場合は大丈夫なのでしょうか? DBのコネクションはクラス変数で、外部のクラスをnewしております。 ここで取得したコネクションクラスをまた別クラスの引数に渡したり・・・。 よろしくお願いします。 (^^ゞ

  • TAKATON
  • ベストアンサー率62% (17/27)
回答No.5

>単純にsynchronizedでないstaticなメソッドは、マルチスレッド下における値の保証はなされませんよね? 単純にsynchronizedでないstaticなメソッドを呼び出した場合、メソッドの中でアクセスしているstatic変数に関しては、保証されません。これは、synchronizedでないインスタンスメソッドの場合と全く同じです。 >結局、synchronizedでないstaticなメソッドとは、一体何なのでしょう??? synchronizedでないstaticなメソッドは以下の条件下で使用されることが多いです。 条件1 引数で与えられた値をもとに何かしらの計算を行い、単純に結果を返すだけのユーティリティ的な処理実装として使用する。 この場合、更新可能なstatic変数へのアクセスが無ければメソッドをsynchronizedにする必要はないですよね。 条件2 クラス内にステータス情報などを保持する必要がない。 クラス内にステータス情報などを保持する必要がないのだから、そもそも呼び出すたびに毎回クラスのインスタンスを生成する必要もない。 条件1、2は多少重複した内容になっていますが、ご理解を促進するために、あえて書きました。

taka451213
質問者

お礼

こんにちは。 何度もありがとうございます。 だんだんわかってきたような気がしますが・・・、 もう少しだけ教えてください。 回答の条件1の場合ですが、例えば・・・、 public static String test(String string, int len){ return string.substring(len); } のような単純なメソッドの場合、staticでもよいという事でしょうか? 値が保証されないのを承知で、あえてstaticなのでしょうか? メモリ上に1箇所しかないので、インスタンスオブジェクトのように逃げ道がない・・・。 同時参照に対する危険性は高いように感じるのですが・・・。 やっぱり理解してないですね・・・。 (^^ゞ

  • TAKATON
  • ベストアンサー率62% (17/27)
回答No.4

まず、static修飾子をつけたメソッドや変数と、そうでないもの(インスタンスメソッド、インスタンス変数)の違いは、その存続期間であると思います。 staticメソッドや変数は、そのクラスがロードされてからJVMが終了するまで存続しますが、インスタンスメソッドや変数は、newキーワードでクラスが生成されてから、GCでそのインスタンスが回収されるまで(厳密には、そのインスタンスがどこからも参照されなくなるまで)です。 この違いをご理解ください。 次に、staticメソッドや変数とインスタンスメソッドや変数において、それらへのアクセスの可能性ついて考えると、ご存知のとおり、staticメソッドや変数はクラス参照ですので、そのクラスがロード可能であればどこからもアクセスできます。一方、インスタンスメソッドや変数へはそのオブジェクトのインスタンスを知っているものだけがアクセスできますよね。 従って、staticメソッドや変数はどちらかというとグローバルなものとして扱われるのに対し、インスタンスメソッドや変数はローカルなものとして扱われます。 しかし、インスタンスメソッドや変数もそのオブジェクトのインスタンスをプログラムのどこからでもアクセスできようにしたり、公開してしまうと一転してグローバルなものになってしまいます。 そういう意味で、マルチスレッド環境におけるメソッドや変数への同時アクセス問題については、その対象がstaticメソッドや変数であろうが、インスタンスメソッドや変数であろうが関係ないわけです。一般的に、インスタンスメソッドをsynchronizedにする場合は、そのメソッドにより同時に複数のスレッドからそのオブジェクトのインスタンス変数へ読み書きが発生する場合に行いますよね。staticメソッドをsynchronizedにする場合もそれと同じで、static変数への読み書きの一貫性を保証するために行います(staticメソッドをsynchronizedにすると、ロックの対象がそのクラスそのものになるから、このようなことができます)。 static修飾子を使用することに対してのメリットデメリットはご理解されているようなので、ここでは触れません。

taka451213
質問者

お礼

こんにちは。 回答ありがとうございます。 非常にわかりやすく解説していただき、この私でも、なんとなくわかったように気がします。 マルチスレッド環境下におけるスレッドセーフの設計という観点から、synchronizedに対する理解はしているつもりなのですが・・・。 単純にsynchronizedでないstaticなメソッドは、マルチスレッド下における値の保証はなされませんよね? インスタンスメソッドの場合、各スレッドとインスタンスオブジェクトとの同期化がなされている限りにおいては、値は保証されるものと理解していますが・・・。 結局、synchronizedでないstaticなメソッドとは、一体何なのでしょう??? ・・・やっぱりわかってないですね・・・。 (^^ゞ

  • nazo-nazo
  • ベストアンサー率39% (17/43)
回答No.3

メリット 私の場合は、ImageIcon(画像URL)などは、インスタンス化する毎に画像を取得するとレスポンスに影響するのでstaticを利用します。 後は、javaのAPI(JavaDoc)を見て下さい。メリットが多少なりに見えてくるかと思います。 デメリットは、No2さんの記載通り、スレッド安全でなくなるだと思います。

taka451213
質問者

お礼

こんにちは。 回答ありがとうございます・・・。 自分なりにいろいろ調べたのですが、メリットとしては、レスポンスの向上、クラス参照可・・・。 安全性を考えると(ここが勘違いしているのかも知れませんが)、あまりメリットではないような気がします・・・。 定数(変数)や、常に同じreturnを保証したい場合の単純なメソッドなどには、問題なく使用できるかと思いますが、 引数によって内部の処理が分岐し、さらに別のクラスやメソッドを参照して複雑、かつ時間のかかる処理をおこなう場合、staticにするとまずいのかな・・・?と思ってしまいます・・・。 >>デメリットは、No2さんの記載通り、スレッド安全でなくなるだと思います。 やっぱりそうなんでしょうか・・・? (^^ゞ

  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.2

 こんばんは。  かなり混乱されているみたいですね。 >なぜ結果が保証されるのかがわかりません・・・。 >synchronizedでない場合、同時アクセスに対するスレッドの制御は、 >どのようになっているのでしょうか?  スレッドとオブジェクトがごちゃごちゃになってきてるみたいですね。  スレッドとオブジェクトは直交した概念です。  わかりやすく言うとお互い直接には関係がありません。  スレッドとRunnableインターフェースを装備したクラスのインスタンスがくっついているような錯覚をよく起こしますが、基本的に間違いです。  スレッドの制御は、どのインスタンスにもアクセス可能ですし、クラスメソッドにも飛びます。  つまり、それが静的なクラスメソッドであろうとインスタンスメソッドであろうと、複数のスレッドが同時にアクセスする可能性があるのなら、同期化の問題が発生する訳です。 >returnには、それぞれの参照クラスで意図した >値が戻されるのでしょうか?  もちろん、それがクラスメソッドであろうと、インスタンスメソッドであろうと、そのメソッドに複数のスレッドが同時アクセスし、内部の変数がめちゃめちゃになって変な戻り値になってしまうということはあります。  しかし、というよりは、この質問はもしかして、「staticなメソッドの戻り値はstaticな変数が帰ってくる」という勘違いをなさってるのではないですか?

taka451213
質問者

お礼

こんにちは。 回答ありがとうございます。 >>スレッドとオブジェクトは直交した概念です。 >>わかりやすく言うとお互い直接には関係がありません。 うーん、ここがよく理解できてないのかも知れません・・・。 インスタンスメソッドの場合、メモリ上に複数存在していますよね? 同期化している場合、各スレッドに対して各インスタンスオブジェクトが存在し、スレッドの並列処理でも、それぞれのオブジェクトで違った処理がおこなわれるように思ってました・・・。 これがstaticだと、メモリ上に1箇所しか存在し得ないので、synchronizedでない場合、各スレッドによる同時参照が起こり得る・・・、と思ったのですが・・・。 >>「staticなメソッドの戻り値はstaticな変数が帰ってくる」という勘違いをなさってるのではないですか? そのようです・・・。 そうでない場合、何故なのかがわかりません・・・。 (微妙なタイミングの、超レアなケースとして) (^^ゞ

  • suzukikun
  • ベストアンサー率28% (372/1325)
回答No.1

Cと混乱していらっしゃるのかもしれません。 JavaでのstaticはClassメソッドになります。(のはずです、すみません)

参考URL:
http://www.javaroad.jp/java_class9.htm
taka451213
質問者

お礼

こんばんは。 回答ありがとうございます。 クラスメソッドです・・・すみません・・・。 このクラスメソッドが、オブジェクトをインスタンス化せずに参照できる利点があるのはわかりますが、 なぜ結果が保証されるのかがわかりません・・・。 synchronizedでない場合、同時アクセスに対するスレッドの制御は、どのようになっているのでしょうか? returnには、それぞれの参照クラスで意図した値が戻されるのでしょうか? 引き続き、よろしくお願いします・・・。 (^^ゞ

関連するQ&A

専門家に質問してみよう