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

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

ただいまの
回答率

90.53%

  • Java

    13751questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    681questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • マルチスレッド

    52questions

    マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

  • スレッドセーフ

    15questions

    マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

マルチスレッド、スレッドセーフがいまいちわからない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,180

lupus_dingo

score 252

今まで避けてきたワードなのですが、
そうも行かなくなりそうなので質問させてください。

シングルスレッド、マルチスレッド、スレッドローカル、シングルトン、プロトタイプなどのキーワードで検索してみたのですがいまいち理解できません。

以下の認識で合っているか教えて下さい。
前提はspringframeworkを使用したWebアプリです。

・シングルトン
システムで1インスタンスを使い回す。
つまり、アプリが起動して最初にインスタンス生成されたものをずっと使い回す。当たり前だがリクエストごとの状態を持たせてはいけない。

・シングルスレッド
一つのスレッドで全ての処理が行われる実行環境。
一つのインスタンスに同時にアクセスされることがないため安全だが効率が悪い。
(リクエストの概念がないバッチアプリは一回実行されるだけなのでシングルスレッド?)

・マルチスレッド
複数のリクエストを同時に処理する実行環境。
現在のJavaプログラムはこれ?
スレッドローカルでないクラス変数は全て同時にアクセスされる可能性があるので、リクエストごとの状態を持つインスタンスはクラス変数にしてはいけない(必ずメソッド内で定義&インスタンス生成)。

・スレッドローカル
threadLocalを使用して作成したクラス変数のこと。
シングルトンならシステムで1インスタンスだが、スレッドローカルはスレッド(≒リクエスト?)ごとに1インスタンスだから、例えば、
多くのメソッドで必要になる変数だがメソッドの引数に毎回同じ指定なんてしたくない場合に便利。

・スレッドセーフ
マルチスレッド環境でも同時に処理されることがないクラス変数。以下のようにしてsynchronizedで囲むだけ。排他がかかるのでパフォーマンスは落ちる。

synchronized(変数){
//指定した変数に対して行う処理。
//この中に書いた処理は全て終了するまで排他制御がかかる。
}

これらについて認識合っているか教えて欲しいです。
よろしくお願いします。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+5

おおざっぱな理解のための例え話をしようと思います。


例えば管理者(あなた)と作業者Aさんが居たとします。Aさんは、あなたから渡される指示書に書かれたことを行います。

あなたはAさんに三枚の指示書を渡しました。Aさんは渡された指示書を、渡された順にこなしていきます。これがシングルスレッドです。作業者が一人しかおらず、作業も渡された順に一つずつこなす状態です。

ここに作業者Bさんが合流しました。BさんもAさんと同じように渡された指示書に書かれたことを行う人です。

今度はAさん、Bさんに同時に別々の指示書を渡しました。AさんBさんはそれぞれ自分に渡された指示書をこなします。これがマルチスレッドです。作業者が二人以上おり、同時並行で作業が進みます。

Aさん、Bさんは作業の進行を円滑に行うために、それぞれ自分用のメモ帳を持っています。これがスレッドローカルです。Aさんのメモ帳はAさんしか見ませんし、Bさんのメモ帳はBさんしか見ません。

あなたは机の上に大きな模造紙を一枚だけ用意しました。この模造紙にある計算結果をどんどん書いてもらうことが目的です。一枚しか用意しないので、作業者は間違えようがありません。これがシングルトンです。全作業者が共通で持つ、全体で1つしかないことが保証されたものです。

AさんBさんにそれぞれ「こういった計算をして、この模造紙にどんどん書いていってほしい」という指示書を出しました。AさんBさんはそれぞれ自分の手元のメモ帳を使って計算し、計算が終わり次第模造紙に書くことにしました。

しかしここで問題が起きます。AさんとBさん、交互に模造紙に書けばいいものを、同時に模造紙に書き始めてしまいました。Aさんが書いた文字、Bさんが書いた文字が入り乱れてわけがわからないものが出来上がります。これではまずいということで、模造紙に書くときは「作業中です」という札を立てて、お互いが干渉しないルールを作りました。これがスレッドセーフです。

 まとめ

  • シングルスレッドは作業者が一人しかおらず、渡された処理を渡された順にこなしていく
  • マルチスレッドは作業者が二人以上おり、それぞれの作業が同時に進む
  • 作業者ごとにスレッドローカルと呼ばれるメモ帳のようなものを持っている
  • 全作業者がアクセス可能で、全体に一つしかないものがシングルトン
  • スレッドセーフにしないとお互いが影響しあってまずいことになる

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/13 11:01

    シングルトンの説明が抜けていたので追記しました。

    キャンセル

+2

私もそんなにマルチスレッドに関しては詳しいわけではないのですが1点だけ。

・スレッドセーフ
マルチスレッド環境でも同時に処理されることがないクラス変数。以下のようにしてsynchronizedで囲むだけ。排他がかかるのでパフォーマンスは落ちる。

synchronized(変数){
//指定した変数に対して行う処理。
//この中に書いた処理は全て終了するまで排他制御がかかる。
}

synchronizedしているものだけがスレッドセーフというわけではありません。マルチスレッドで同時処理する場合に問題が起こるのは、Chironianさんも説明されていますが、各スレッドのタイミングの問題で変数の変化が想定通りの回数起こらない場合などです。変化しないものであれば、つまり読み取り専用であればどのスレッドからどのタイミングで参照されても値は同じなのでスレッドセーフということになります。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/13 07:18

    >変化しないものであれば、つまり読み取り専用であればどのスレッドからどのタイミングで参照されても値は同じなのでスレッドセーフということになります。

    確かにそうでした。
    回答ありがとうございます。

    キャンセル

+1

こんにちは。

まず、「スレッド」の概念は理解されていますでしょうか?

プログラムを実行する「主体」みたいなものですね。それをスレッドと呼びます。プロセスが起動されたら、そのエントリーポイント(CやC++はmain()関数です。Javaはmain()メソッド?)からスレッドが実行を開始します。
この時点ではシングル・スレッドです。そのまま、サブスレッドを起動しなかった場合はシングル・スレッドのまま動作を継続します。最後にmain()からリターンするなどによりプログラムを終了します。

サブスレッドを起動するとマルチ・スレッド・プログラムとなります。同じプロセス内で起動されたスレッドは、同じプロセス内にあるメモリにアクセスできます。

今、ある変数xがあり、2つのスレッドaとbが変数xをインクリメントすると仮定します。
インクリメントする場合、そのメモリの内容を読み出して1加えて元のメモリへ書き込みます。これをRead-Modify-Writeといいます。

非常に運が悪く、2つのスレッドが変数xを同時にインクリメントしたとします。x==0の時に2つのスレッドがインクリメントした場合でも、期待する結果はx==2となることですね。

さて、同時と言っても同じメモリを全く同時にアクセスすることはできないよう、コンピュータのハードウェアが調整します。その結果、下記の順序でアクセスしたと仮定します。

  1. スレッドaがread
  2. スレッドbがread
  3. スレッドaが読み出した値をインクリメント(1になる)
  4. スレッドbが読み出した値をインクリメント(1になる)
  5. スレッドaがwrite(xが1になる)
  6. スレッドbがwrite(xは1のまま)

ということで、残念ながら期待通りの動作になりません。

これがマルチ・スレッドの危険性です。もちろんインクリメントに限りません。他にも様々なパターンのリスクが存在しています。

このリスクを回避する仕組みを備えている機能は「スレッドセーフ」と呼ばれます。
また、スタック上のメモリとスレッド・ローカル・ストレージ上のメモリはそれを所有しているスレッドだけがアクセスできますので、安心してアクセスできます。逆にそれ以外のメモリは全てリスクを抱えています。
複数のスレッドが同時にアクセスすることがないよう、複数のスレッドで共有しないようにしたり、共有する場合はミューテックスで排他制御したりします。

因みに、シングルトンやスレッド・ローカル・ストレージは一種のグローバル変数ですから、使わないで済む場合はなるべく使わない方が良いです。(必要な時は当然使うべきですが)これはシングル・スレッド・プログラムの場合となんら変わりません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/13 07:24

    丁寧な回答ありがとうございます。

    >この時点ではシングル・スレッドです。そのまま、サブスレッドを起動しなかった場合はシングル・スレッドのまま動作を継続します。

    サブスレッドを起動するかしないかは何によって変わるのでしょうか?

    >同じプロセス内で起動されたスレッドは、同じプロセス内にあるメモリにアクセスできます。

    なるほど勉強になります。

    >因みに、シングルトンやスレッド・ローカル・ストレージは一種のグローバル変数ですから、使わないで済む場合はなるべく使わない方が良いです。

    スレッド・ローカル・ストレージとはなんでしょうか?

    キャンセル

  • 2017/11/13 14:13

    > サブスレッドを起動するかしないかは何によって変わるのでしょうか?

    Javaの詳しいことは把握していませんが、↓などの方法で起動します。
    http://www.itsenka.com/contents/development/java/topics/thread2.html
    これらのような何らかの方法で起動しているかどうかです。
    使っているライブラリやフレームワークが(こっそり)起動していることもあります。

    > スレッド・ローカル・ストレージ

    スレッド毎に設けられたstatic変数です。Javaでは、本当にstaticなのかどうかよく把握していませんが、いくつかあるサンプルを見る限りでは皆さんstaticメンバ変数に設定しています。

    staticメンバ変数はちょっと油断(publicにしたりアクセサを設けたり)すると直ぐに事実上のグローバル変数になりますから要注意なのです。

    キャンセル

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

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

関連した質問

  • 解決済

    StringBuilderとStringBufferの違いについて

    Javaで文字列の連結処理に使うAPIは 主にStringBuilderクラスとStringBufferクラスの2種類あると思うのですが、 どう違うのでしょうか? 使い分けのポイ

  • 解決済

    スレッドセーフとは?

    お世話になります。 ある記事にて「Invoke,BeginInvoke,EndInvoke...等」メソッドはスレッドセーフが保障されているとありました。 スレッドセーフとは複

  • 解決済

    Struts1.xを使用したスレッドセーフについて

    Struts1.xではActionは1つしかインスタンス生成してくれないので、スレッドセーフにするために何かしら対策を行う必要があると思います。 ネットで調べると、例えばSprin

  • 解決済

    このプログラムについて教えて下さい(singletonパターン)

    public class TicketMaker {     private  static TicketMaker singleton = new TicketMaker();

  • 受付中

    マルチスレッドのテストについて

    Javaでマルチスレッドのプログラムを書いています。 しかしどのようにマルチスレッドのテストを書けばいいのかがよく理解できていません。 あるstatic変数countに複数

  • 解決済

    [Java]synchronizedブロックの使用箇所

    前提・実現したいこと synchronizedブロックを使用する箇所が、一般的な書き方ではどこになるのかが気になりました。 該当のソースコード public class

  • 受付中

    Javaのパフォーマンスチューニング

    ■概要 Tomcat上で動作しているWebアプリが急にスローダウンする現象が発生し、原因追及に困っております。 スレッドダンプの状態などからアプリケーションのロジックそのものよ

  • 解決済

    スレッドセーフについて

    スレッドセーフについて教えてください。 言葉の意味自体は複数のスレッドから制御が走った場合に、データの整合性が取れないものという理解をしています。 以下の、コードにおいてはCo

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

  • Java

    13751questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Spring

    681questions

    Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

  • マルチスレッド

    52questions

    マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

  • スレッドセーフ

    15questions

    マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。