質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

Javaのメモリ共有の仕組について

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,160

score 200

Javaのメモリ共有の仕組みについて教えてください。
privateなどで宣言されたようなヒープ領域にある変数について、スレッドセーフの仕組になっていない場合はメモリ共有(データの書き換え)などが起こり得ると思いますが。
いったい、どのような仕組なのでしょうか。
クラスAにprivateで宣言したA'というオブジェクトがあった場合、A'はヒープ領域に割り当てられると思います。
その後、他のスレッドでもクラスAでの動作があり、A'がヒープ領域に割り当てられる場合、もちろんアドレスは最初に割り当てられたところとは違う箇所に割り当てられますよね?
それでも、書き換えが起こるということは、Javaのなかでスレッド毎に割り当てたアドレスを管理出来てないのでしょうか?
「えーっと、A'のアドレスどこだっけ。あ、ここにA'のオブジェクトがある、きっとここかな。」みたいな感じで間違え得るのでしょうか。
それとも、アドレスを単に間違えるだけではない理由があるのでしょうか。
もし、参考になるようなネットのサイト等も教えて頂けると助かります。
宜しくお願いします。

回答を受け、少し追記します。
・インスタンスはスレッド毎にできます。
・「private オブジェクト名 変数名;」で宣言した変数がデータの書き換えが起こっています。
・メインメソッドをsynchronizedにするとか、上記変数をローカル変数にするとかすれば治ります。

ただ、なぜインスタンスは別なのに起こるのかと思ってまして。
以前、springを使ったときにscopeをprototypeにしたときは問題なかったと思っており、結局インスタンスは別になるのに何が違うんだろうと。
(ここの解釈自体が間違えているのかもしれませんが。)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+2

それでも、書き換えが起こるということは、Javaのなかでスレッド毎に割り当てたアドレスを管理出来てないのでしょうか?
「えーっと、A'のアドレスどこだっけ。あ、ここにA'のオブジェクトがある、きっとここかな。」みたいな感じで間違え得るのでしょうか。
それとも、アドレスを単に間違えるだけではない理由があるのでしょうか。
この文面を見た限りでは Java(JVM) が間違って書き換えてしまうと理解されているようですが、そうではありません。プログラマの実装ミスです。

質問に近いケースを考えると
  1.  Class A のインスタンスを1つ作成。スレッド1,2でこのAのインスタンスを参照する
  2.  Class A のインスタンスをスレッド1,2でそれぞれ生成。(Aのインスタンスが2つある状態)
となりますが、前者は複数スレッドで1つのインスタンスを共有しているので、スレッドセーフに実装しないと意図しないデータの書き換えが起こる可能性があります。
後者はインスタンスが2つあるので書き換えられることはありません。
質問のお話しはたぶん後者のことですよね?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/22 19:05

    >kodaiさん
    そうなのですね。。。
    共有された1つのアクションクラスからスレッド毎にインスタンス生成されたクラスの中でフィールド定義されたもの(ヒープ領域)にされたものは、いくらスレッド別のインスタンスの中とはいえ、書き換えが起こる可能性があるんですね。。。
    それが常ではなくて高負荷の時だけですか、、うーん、納得は行きますが納得いかないですね、これ(笑)

    キャンセル

  • 2015/04/22 19:18

    Struts 1.x / Struts 2.xでのスレッドセーフ(thread safe)について
    http://www.kinusati.net/2009/12/07/struts-1-x-struts-2-x%E3%81%A7%E3%81%AE%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%82%BB%E3%83%BC%E3%83%95thread-safe%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/

    こちらの記事が役に立つかもしれません。「Actionサブクラスにインスタンス変数を持たせてリクエスト毎の状態やメッセージを管理してはいけない」

    キャンセル

  • 2015/04/23 09:01

    一旦解決とさせていただきます。
    色んな状況をもう少し整理します。
    ベストアンサーとして、やりとりをさせていただいたこちらの回答を選ばせて頂きます。
    また、違う形で質問を作っていたら、その時は宜しくお願いします(笑)

    キャンセル

0

もしかしてprivate staticと宣言していませんか?
だとしたら同じクラスの全てのオブジェクトでその変数は唯一の存在になりますので、ご質問の現象が起こる可能性があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/22 10:57

    回答ありがとうございます。
    いえ、privateですね。(私の知識不足だけで、実は暗黙的にstaticになるよ。とかあればそうなのかもしれませんが。)
    単純に「private オブジェクト名 変数名;」で宣言しています。

    キャンセル

  • 2015/04/22 11:33

    念のために確認ですが、「クラスAにprivateで宣言したA'というオブジェクト」は内部にstatic宣言されている変数を持つクラスであったりしませんか?
    ソースを見ることができるのであればオブジェクトA'がどういったものか確認してみてはいかがでしょうか。

    キャンセル

  • 2015/04/22 16:33

    そのオブジェクト内ではstaticで宣言されている変数などはありません。

    キャンセル

0

もしかしたら,Aのインスタンス生成が複数のスレッドから同時に呼び出されたせいで,
その呼び出した複数のスレッドに同じオブジェクトが返っているのではないでしょうか.

そもそもsynchronized修飾子はそういった場合に発生する整合性の問題を解決するために存在します.
読本Java/9.2 ロックとアンロック

例えばCalendar.getInstance()は内部的にはGregorianCalendarの新規インスタンスを生成して返しているだけですが,このメソッドもsynchronizedです.
複数回呼び出されて時刻を操作使用として他の時刻に影響を与えないよう,そうしているのでしょう.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/22 12:54

    回答ありがとうございます。
    結果的にすごく稀なタイミングで同じものが返ってしまった可能性がある。
    ってことがありえるということですか。。
    ちょっと考えたことなかったです、ありがとうございます。

    キャンセル

0

お探しのところと合致してるかは分かりませんが、以下のページを見つけました。

意外と教わる機会の少ないメモリ管理のお話
http://www.ibm.com/developerworks/jp/java/library/j-jtp06197.html

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る