• 検索結果がありません。

Javaと マルチスレッド

N/A
N/A
Protected

Academic year: 2021

シェア "Javaと マルチスレッド"

Copied!
41
0
0

読み込み中.... (全文を見る)

全文

(1)

Javaと

マルチスレッド

(2)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(3)

きっかけ

現場の新人SEより、Webアプリケーションサーバに関して、 以下の質問を受けた。 「ConcurrentModificationExceptionの発生原因について」 質問は、以下のように続いた。 「マルチスレッドで起きる例外のようだが、 シングルスレッドでも起きることがあるのか?」

(4)

きっかけ

Webアプリケーションサーバは

基本的にマルチスレッド環境なんだけど

そのことを理解できていないのかな?

Webアプリケーションサーバにおける マルチスレッドを考慮したプログラミングの 基礎知識をまとめてみました。

(5)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(6)

マルチスレッド対応が必要になる

場面とは?

Javaバッチなどで、明示的に並列処理を行う場合 自分でマルチスレッド処理を組むため、意識できる

Javaアプリケーションサーバ上でのプログラミング (Tomcat, WebSphere, WebLogic, etc.)

アプリケーションサーバ側でマルチスレッド処理部分が行われるため、

基礎知識が不足していれば、自分ではマルチスレッド環境で動く コードだと意識できない場合がある

(7)

Javaサーバサイドプログラミングは

すべてマルチスレッドである!

マルチスレッド起動を行うコーディングをしなくても アプリケーションサーバ自身が並列処理をサポートしている Webアプリケーションサーバ サーブレットAへの リクエスト サーブレットAへの リクエスト サーブレットBへの リクエスト サーブレットA サーブレットB サーブレットC スレッド1:サーブレットA スレッド2:サーブレットA スレッド3:サーブレットB

常にマルチスレッドを

意識したプログラミング

が必要不可欠!

(8)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(9)

プロセスとは?

OSによって実行される、個別のプログラムのこと。 プロセスごとに、専用のメモリが割り当てられる。 (参考)e-words IT用語辞典 http://e-words.jp/w/%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9.html ソフトウェアの世界では、OSからメモリ領域などの割り当てを受けて 処理を実行しているプログラムのことを言う。

(10)

スレッドとは?

並列処理の際の、最小の実行単位のこと (参考)e-words IT用語辞典 http://e-words.jp/w/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89.html ソフトウェアやプログラミングなどの分野で、並列処理に対応したOS 上でのプログラムの最小の実行単位をスレッドという。

(11)

プロセスとスレッドの違い

プロセスは、OSから、専用のメモリ空間を与えられて実行さ れるプログラムの単位。 スレッドは並列処理の最小実行単位。 1つのプロセスに、1つのスレッドしかない場合もある (シングルスレッド) 1つのプロセスに、複数のスレッドがある場合もある (マルチスレッド)

(12)

プロセスとスレッドの概念図

共有メモリ プロセス1 専用メモリ 専用メモリプロセス2 専用メモリプロセス3 ・・・ スレッド1-1 スレッド1-2 スレッド2-1 スレッド3-1 スレッド3-2 ・・・ プロセス1 プロセス2 プロセス3 ・・・ OS 1つのプロセスに複数スレッドがある場合、 スレッド間でメモリは共有される!

(13)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(14)

Javaのメモリ構成図

種類1 種類2 格納対象 共有/個別 ヒープ メモリ Java ヒープ※1 ・オブジェクト(インスタンス)・インスタンス変数 共有 メモリ Permanent ヒープ※2 ・クラス、メソッド情報 ・クラス変数・定数 Native メモリ Cヒープ ・JavaVM自身やNativeコード等 スレッドス タック ・各スレッド毎のローカル変数 スレッド 個別メモリ

(15)

Javaのメモリ構成図

前頁の表について補足。今回は共有メモリとスレッド固有メ モリを明示したかっただけなので詳細説明は省く。

※1…Javaヒープは、New領域(Eden, Survivor0, Survivor1)、 およびOld領域に細分化され、世代管理される。

※2…前頁の表はJava1.7以前のもの。Java1.8では

Permanentヒープが廃止され、Metaspeceが新設されたが、 共有メモリとスレッド個別メモリの分類は変わらない。

(16)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(17)

スレッドセーフとは?

マルチスレッド環境において、他のスレッドの影響を受けず に安全な実行が可能なこと (参考)e-words IT用語辞典 http://e-words.jp/w/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%82%BB%E3%83%BC%E3 %83%95.html マルチスレッド環境で、ライブラリやプログラム、クラスなどが複数 のスレッドから同時に利用されても正常に動作すること。

(18)

スレッドセーフの条件

原則

• 他のスレッドから完全に独立していること

具体的には?

• 他のスレッドと共通のオブジェクト(インスタンス)を参照してい ないこと

(19)

絶対にスレッドセーフなクラス

ローカル変数は使用している インスタンス変数、クラス変数は、状態が不変のもの(定 数)しか参照していない この状態をステートレスという。 ※但し、publicメソッドの引数として渡されるオブジェクトが、 共有オブジェクトであった場合は、スレッドセーフではなくなる。 →厳密にスレッドセーフを意識するなら、引数のオブジェクトを コピーして、そちらを使うなどの考慮が必要?

(20)

絶対にスレッドセーフなクラス

<サンプルソース1>

public class SampleA extends HttpServlet { private final String HTML =

"<HTML>" + "<BODY>" +

"Hello World !" + "</BODY>" +

"</HTML>" ;

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, java.io.IOException {

PrintWriter out = res.getWriter(); out.println(HTML); } } HttpServletのサブクラス として、SampleAクラス を作成 doGetメソッドを作成 PrintWriterオブジェクトを取 得し、ローカル変数に格納し printlnメソッドでHTML出力 HTMLはインスタ ンス変数だが、 final Stringのため 不変オブジェクト

(21)

絶対にスレッドセーフなクラス

<サンプルソース1>

スレッド1用スタック out req res スレッド 1 スレッド2用スタック out req res スレッド 2 共有メモリ領域 PrintWriterオブジェクト HttpServletRequestオブジェクト HttpServletResponseオブジェクト PrintWriterオブジェクト HttpServletRequestオブジェクト HttpServletResponseオブジェクト SampleA オブジェクト HTML (定数) SampleAクラスのdoGetメソッドに複数スレッドから同時に アクセスされた場合

(22)

状況次第でスレッドセーフなクラス

ローカル変数は使用している クラス変数は、状態が不変のもの(定数)しか 参照していない インスタンス変数は参照・使用しているが、そのクラスのイ ンスタンスは、複数スレッドからアクセスされることがないこ とが明らかである。

(23)

状況次第でスレッドセーフなクラス

<サンプルソース2 その1>

public class SampleB extends HttpServlet { private final String HTML =

"<HTML><BODY>" + “Name: %s" +

"</BODY></HTML>" ;

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, java.io.IOException {

PrintWriter out = res.getWriter(); SampleBForm form = new SampleBForm(); form.setName(req.getParameter(“NM”)); out.println(String.format(HTML, form.getName())); } } HttpServletのサブクラス として、SampleBクラス を作成 SampleBFormオブジェクトを 作成し、リクエストパラメー タを格納 HTML内に変数埋 め込み箇所を定義 格納したformから値を取り出 し、HTMLに埋め込んで出力

(24)

状況次第でスレッドセーフなクラス

<サンプルソース2 その2>

public class SampleBForm {

private String name;

public String getName() { return this.name;

}

public void setName(String name) { return this.name = name;

}

}

1つのインスタンス変数と、 getter, setterメソッドを定義

(25)

状況次第でスレッドセーフなクラス

<サンプルソース2 その2>

スレッド1用スタック out req res スレッド1 共有メモリ領域 PrintWriter Obj. HttpServletRequest Obj. HttpServletResponse Obj. SampleB Obj. HTML(定数) SampleBクラスのdoGetメソッドに複数スレッドから同時に アクセスされた場合

form SampleBForm Obj.

name SampleBForm Obj. name スレッド2用スタック out req res スレッド2 PrintWriter Obj. HttpServletRequest Obj. HttpServletResponse Obj. form

(26)

スレッドセーフではないクラス

複数スレッドから参照されているインスタンスが、インスタ

ンス変数を参照・使用している

または

(27)

スレッドセーフではないクラス

<サンプルソース3>

public class SampleC extends HttpServlet { private final String HTML =

"<HTML><BODY>" + “Time: %s" +

"</BODY></HTML>" ;

private static final SimpleDateFormat sdf

= new SimpleDateFormat(“yyyy-MM-dd HH:MM:SS”);

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, java.io.IOException {

PrintWriter out = res.getWriter();

out.println(String.format(HTML, sdf.format(new Date()))); } } HttpServletのサブクラス として、SampleCクラス を作成 クラス変数として SimpleDateFormatを 定義 doGetメソッド内から SimpleDateFormat#format メソッドを呼び出し ※スレッドセーフではない ことで有名

(28)

スレッドセーフではないクラス

<サンプルソース3>

スレッド1用スタック out req res スレッド1 共有メモリ領域 PrintWriter Obj. HttpServletRequest Obj. HttpServletResponse Obj. SampleC Obj. HTML(定数) SampleCクラスのdoGetメソッドに複数スレッドから同時に アクセスされた場合 SampleC クラス定義情報 sdf SimpleDateFormat オブジェクト format() スレッド2用スタック out req res スレッド2 PrintWriter Obj. HttpServletRequest Obj. HttpServletResponse Obj.

(29)

確実にスレッドセーフを担保する

ための基本方針

インスタンスが複数スレッドから参照されるクラスの場合 • ローカル変数は使用可能 • インスタンス変数・クラス変数は、定数の参照のみ可能 インスタンスが複数スレッドから参照されないクラスの場合 • ローカル変数・インスタンス変数は使用可能 • クラス変数は、定数の参照のみ可能

(30)

JavaEEの主なフレームワークの

マルチスレッド対応

フレーム ワーク Controllerクラス インスタンスの複数ス レッド共有 クラス 変数 インスタンス 変数 JavaEE標準 HttpServlet 有り(基本的に流用) NG NG Apache

Struts Action 有り(Singleton) NG NG Seasar2 SAStruts Action 無し(リクエスト毎) NG OK Spring Web MVC Controller 有り(Singleton) ※設定次第では無し NG NG ※設定次 第ではOK ※Spring Frameworkにおいては、インスタンスの生成スコープを設定変更できるため、呼び出し毎、 またはリクエスト毎にインスタンスを生成する設定にすれば、複数スレッドからの共有はされない。

(31)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(32)

複数スレッドの競合で正しい処理が

できなくなる典型パターン

read-modify-write: 読み取って変更して書き戻す check-then-act: チェックした結果に基づいて処理 check-if-absent: チェックしてなければ置き換える いずれも、状態を読み取り、その結果に基づき行動するが、 並列処理では、行動する前に他スレッドにより、その行動する 前提の状態が書き換わってしまい、うまくいかなくなる。 (参考) http://jis.hatenablog.com/entry/20100731/1280557752 http://wiki.javazuki.com/concurrent-race-condition

(33)

ConcurrentModificationException

CollectionクラスをIteratorを使ってループ中に、その Collection自体に対して変更操作を行った際に発生する。 主にマルチスレッド環境で発生する例外だが、 シングルスレッド環境でも、たとえば、ループ内で 自分自身の要素を削除しようとすれば発生する。 回避策としては、Iteratorを使わないという原始的な方針もあ るが、並行Collectionクラスを使う方法が推奨。 ただ、それだけでは根本解決しないことも多いので注意。 (参考) http://futurismo.biz/archives/2811

(34)

スレッドセーフ基本方針が

満たせない場合の対応方針

複数スレッドからアクセスされる可能性のある箇所のなかで、 共有変数を参照・更新するような、特に注意すべき箇所 に対しては、以下のような対応が有効となる。 1. 複数スレッドが同時にアクセスしないよう、 同期化(Synchronized化)する 2. Atomic型のクラスを利用(java.util.concurrent.atomic) 3. 並行Collectionクラスを利用(java.util.concurrent) 4. スレッド毎に個別のデータを格納できる ThreadLocalクラスを利用

(35)

同期化(Synchronized化)

前述のような、競合時に問題となる処理に対して、 synchronized化し、一連の処理が分割実行されないようにする。 ただ、並列性が損なわれ、パフォーマンス低下を招く危険が あるため、注意が必要。 Atomic型や、並行Collectionクラスを利用することで 解決する場合はそちらが推奨される。

(36)

Atomic型

int counter=0; counter++; といった、一見1つの処理のように見えて、実は、①読み取り ②1加算③書き込み、という複合操作になっているような操作 を、Atomicな操作(分割されない最小単位の操作)として実 行させることができるクラス。Java1.5で導入。

AtomicInteger counter = new AtomicInteger(0); counter.AddAndGet(1);

(37)

並行Collection型

並列なアクセスに対応したCollectionクラス。Java1.5で導入。 先に述べたConcurrentModificationExceptionが発生しない。 ConcurrentHashMap Iteratorループ中に別スレッドが値を更新しても、直前の更新を反 映した値が取得できる(但し確実ではない) CopyOnWriteArrayList Iteratorや、更新処理時、Collectionのコピーを生成し、競合が起き ないように処理する。かなりコストが高いが、更新頻度よりループ 処理などのデータ走査頻度が多い場合にメリットがある。 (参考) http://software.fujitsu.com/jp/technical/interstage/apserver/guide/pdf/ConcurrentMap.pdf http://wiki.javazuki.com/concurrent-race-condition http://d.hatena.ne.jp/j5ik2o/20090813/1250118023

(38)

ThreadLocal

スレッドごとの固有情報を保存することができ、マルチス レッド環境における競合回避には、非常に便利です。

ThreadLocal<String> str = new ThreadLocal(“abc”); 但し、Webアプリケーションサーバ上で使う場合、メモリ リークが起きる場合があるようです。

もし利用する場合は、確実にThreadLocal#removeするように 心がけることが重要になりそうです。

(39)

目次

1. きっかけ 2. マルチスレッド対応が必要になる場面とは? 3. Javaのプロセスとスレッドについて 4. Javaのメモリ構成について 5. スレッドセーフについて 6. スレッド間競合における問題の回避策あれこれ 7. まとめ

(40)

まとめ

Javaサーバサイドのプログラミング(Javaアプリケーション サーバなどを利用)の場合、マルチスレッドの考慮は必須! スレッドセーフなサーブレットの基本はステートレス (ローカル変数以外使わない) どうしてもそうできない場合は、Synchronized化、Atomic型、 並行Collection、ThreadLocalなどのクラスも使いながら、 スレッドセーフなコーディング方法をきっちり考えよう。

(41)

ご清聴

ありがとう

参照

関連したドキュメント

glturcwllich,th4)ugllmEndebymimyminds&#34;w(DIII(IseemillcWnrkOfaSinglcmi加d9

といったAMr*&#34;&#34;&#34;erⅣfg&#34;'sDreα

&#34;A matroid generalization of the stable matching polytope.&#34; International Conference on Integer Programming and Combinatorial Optimization (IPCO 2001). &#34;An extension of

The reported areas include: top-efficiency multigrid methods in fluid dynamics; atmospheric data assimilation; PDE solvers on unbounded domains; wave/ray methods for highly

[r]

&lt; &gt;内は、30cm角 角穴1ヶ所に必要量 セメント:2.5(5)&lt;9&gt;kg以上 砂 :4.5(9)&lt;16&gt;l以上 砂利 :6 (12)&lt;21&gt; l

Rumsey, Jr, &#34;Alternating sign matrices and descending plane partitions,&#34; J. Rumsey, Jr, &#34;Self-complementary totally symmetric plane

McKennon, &#34;Dieudonn-Scwartz theorem on bounded sets in inductive limits&#34;, Proc. Schwartz, Theory of Distributions, Hermann,