<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>並列処理</title><link>http://blogs.wankuma.com/nagise/category/1447.aspx</link><description>並列処理</description><managingEditor>凪瀬</managingEditor><dc:language>ja-JP</dc:language><generator>.Text Version 0.95.2004.102</generator><item><dc:creator>凪瀬</dc:creator><title>アクターモデルでは同期は考慮外？</title><link>http://blogs.wankuma.com/nagise/archive/2007/11/15/108501.aspx</link><pubDate>Thu, 15 Nov 2007 16:25:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/11/15/108501.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/108501.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/11/15/108501.aspx#Feedback</comments><slash:comments>15</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/108501.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/108501.aspx</trackback:ping><description>&lt;P&gt;&lt;A href="http://bbs.wankuma.com/index.cgi?mode=al2&amp;amp;namber=9496"&gt;オブジェクト指向熱イベントパネルディスカッション検討スレッド&lt;/A&gt;でオブジェクト指向から話がそれて並列処理の話になってしまったのですが、そこで出てきたのが &lt;A href="http://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%AF%E3%82%BF%E3%83%BC%E3%83%A2%E3%83%87%E3%83%AB"&gt;アクターモデル&lt;/A&gt;というものでした。&lt;/P&gt;
&lt;P&gt;さて、Wikipediaの解説などを見ているとマルチスレッド特有の &lt;A href="http://ja.wikipedia.org/wiki/%E5%90%8C%E6%9C%9F_%28%E6%83%85%E5%A0%B1%E5%B7%A5%E5%AD%A6%29"&gt;同期&lt;/A&gt;の問題について触れていないように思ったわけです。&lt;BR&gt;いや、そもそもアクターモデルでは非同期のメッセージのやり取りがあるわけで、時系列操作は考えてはいけないのでしょうから正しくは&lt;STRONG&gt;分散トランザクションの問題&lt;/STRONG&gt;というのが正しいのでしょう。&lt;/P&gt;
&lt;P&gt;アクターそれぞれが状態を持つことになるでしょうが、ある「状態」を複数のスレッドで処理する場合、つまり、複数のアクターがあるアクターが持つ単一の「状態」を元になんらかの処理を行う場合、元になる状態が可変であるとシステム全体で情報の不整合が発生しうるということです。&lt;/P&gt;
&lt;P&gt;そして、この状態の不整合を起こさないようにどうすればよいかというのが&lt;STRONG&gt;分散トランザクション&lt;/STRONG&gt; の関心ごとで別のパラダイムとして議論されているのかな、と思った次第。&lt;/P&gt;
&lt;P&gt;いずれにせよ、プログラムをする際にはデータの整合性について考慮しないわけにはいかず、そのための同期処理で苦労するわけなのですが、この苦労は分散トランザクションに答えを求めるのが正しいのかもしれませんね。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/108501.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>SimpleDateFormatでNumberFormatException</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/30/105044.aspx</link><pubDate>Tue, 30 Oct 2007 21:17:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/30/105044.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/105044.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/30/105044.aspx#Feedback</comments><slash:comments>1214</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/105044.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/105044.aspx</trackback:ping><description>&lt;p&gt;障害報告を受けて調査していると、
&lt;a href="http://java.sun.com/javase/ja/6/docs/ja/api/java/text/DateFormat.html#parse(java.lang.String)"&gt;
SimpleDateFormat#parse()&lt;/a&gt;でNumberFormatExceptionが出ていました。&lt;/p&gt;
&lt;p&gt;ドキュメントにあるように変換に失敗したときはParseExceptionがthrowされるものだと思っていたので、
すわバグパレード行きかと思ったら、どうやらSimpleDateFormatをマルチスレッド環境下で使った場合の問題らしいことが判明。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.geocities.co.jp/Playtown/1245/java/unsafe_simple_date_format.html"&gt;
java.text.SimpleDateFormat はスレッドセーフではない&lt;/a&gt;がよくまとまっています。&lt;/p&gt;

&lt;p&gt;SimpleDateFormatをマルチスレッド下で使ってはならないというtipsは知っていたのですが、
その場合の症状としてNumberFormatExceptionがthrowされることがある、というのは知りませんでした。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/105044.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>WEBで重い処理の進捗を表示する</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/11/101532.aspx</link><pubDate>Thu, 11 Oct 2007 18:02:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/11/101532.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/101532.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/11/101532.aspx#Feedback</comments><slash:comments>109</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/101532.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/101532.aspx</trackback:ping><description>&lt;p&gt;Webアプリケーションで時間の掛かる処理をキックする場合、進捗表示をしたくなることがあります。&lt;br&gt;
Threadを立てて裏で処理するようにすれば可能なのですが、いろいろと面倒があるのでざっくり指針を書いてみたいと思います。&lt;/p&gt;

&lt;h4&gt;HTMLから定期的にアクセスする&lt;/h4&gt;

&lt;p&gt;進捗状況を知るために、HTML側から定時で繰返しアクセスさせる必要があります。&lt;br&gt;
METAタグを使ってリロードさせる手法が一般的ですね。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&amp;lt;META HTTP-EQUIV="Refresh" CONTENT="5"&amp;gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;上記例では5秒ごとのリロードです。&lt;/p&gt;
&lt;p&gt;この方式だとページ全体を読み直すわけですが、
格好良くしようと思えばAJAX的手法を使って非同期通信する手法もあります。&lt;/p&gt;
&lt;p&gt;とにかく、サーバに低的にアクセスします。これをポーリング(polling)といいます。&lt;/p&gt;

&lt;h4&gt;サーバ側ではセッションにThreadの管理オブジェクトを保管する&lt;/h4&gt;

&lt;p&gt;サーバ側ではThreadの管理オブジェクトをセッションに格納して管理します。
以下はJavaでのコーディング例。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;import&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;java.util.Timer;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;import&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;java.util.TimerTask;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;extends&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Thread&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;状態ステータス&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;enum&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Status&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;開始待ち&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;READY,&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;実行中&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;RUNNIG,&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;正常終了&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;FINISHED,&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;異常終了&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;ERROR,&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ポーリングのタイムアウト間隔&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;static&amp;nbsp;final&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;long&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;TIMER_DELAY&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#990000"&gt;10000&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;スレッドの状態&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;volatile&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Status&amp;nbsp;status;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;停止用のタイマ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Timer&amp;nbsp;timer;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;コンストラクタ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.status&amp;nbsp;=&amp;nbsp;Status.READY;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;DeamonのTimerを作成&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.timer&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Timer&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;true&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;状態を返す&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Status&amp;nbsp;getStatus&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.status;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;Thread終了タイマーをリセット&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;resetTimer&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.timer.cancel&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.timer.schedule&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Canceler&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;TIMER_DELAY&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;{&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@inheritDoc&lt;/font&gt;&lt;font color="#3f5fbf"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@see&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;java.lang.Thread#start()&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;start&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.status&amp;nbsp;=&amp;nbsp;Status.RUNNIG;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.start&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.resetTimer&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;処理結果を返す&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;getData&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ここではダミー実装なのでnullを返しているが、&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;必要な情報を格納したオブジェクトであるべき&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;エラー結果を返す&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;getError&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ここではダミー実装なのでnullを返しているが、&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;必要な情報を格納したオブジェクトであるべき&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;{&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@inheritDoc&lt;/font&gt;&lt;font color="#3f5fbf"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@see&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;java.lang.Thread#run()&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;run&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;try&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;while&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;!&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.isInterrupted&lt;/font&gt;&lt;font color="#000000"&gt;())&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ループ処理&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;...&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;TODO&amp;nbsp;処理結果を格納&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;正常終了&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.status&amp;nbsp;=&amp;nbsp;Status.FINISHED;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;catch&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;RuntimeException&amp;nbsp;e&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;異常終了&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.status&amp;nbsp;=&amp;nbsp;Status.ERROR;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;ポーリングの反応がなくなった際に処理を停止させるためのTimerTask&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Canceler&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;extends&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;TimerTask&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;{&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@inheritDoc&lt;/font&gt;&lt;font color="#3f5fbf"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;&lt;/font&gt;&lt;font color="#7f9fbf"&gt;@see&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;java.util.TimerTask#run()&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;run&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;割り込み&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager.&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.interrupt&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;ポイントとしてはループ処理の際、Thread#isInterrupted()を参照してループを回している点。
このほか時間の掛かる処理の前後で中断できるように仕込みを入れておく必要があります。&lt;/p&gt;

&lt;p&gt;そして、10秒後にThreadを停止するタイマーを起動しています。&lt;br&gt;
このタイマーはポーリングによるアクセスでリセットされます。
つまり、途中でユーザがブラウザを閉じるなどのキャンセルを行った場合に、
重い処理を途中で停止させるための仕掛けです。&lt;/p&gt;

&lt;p&gt;一方Servletの方では&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;protected&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;doGet&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;HttpServletRequest&amp;nbsp;request,&amp;nbsp;HttpServletResponse&amp;nbsp;response&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throws&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ServletException,&amp;nbsp;IOException&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;Sessionから管理オブジェクトを取得&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;HttpSession&amp;nbsp;session&amp;nbsp;=&amp;nbsp;request.getSession&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager&amp;nbsp;manager&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;session.getAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;MANAGER_KEY&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;管理オブジェクトがない場合は作成してSessionに格納&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;manager&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;manager&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ThreadManager&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;session.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;MANAGER_KEY,&amp;nbsp;manager&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;String&amp;nbsp;dispatchUrl;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;switch&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;manager.getStatus&lt;/font&gt;&lt;font color="#000000"&gt;())&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;case&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;READY:&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;Threadの開始&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;manager.start&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ポーリング画面を表示&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;dispatchUrl&amp;nbsp;=&amp;nbsp;URL_POLLING;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;case&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;RUNNIG:&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;Thread停止タイマをリセット&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;manager.resetTimer&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ポーリング画面を表示&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;dispatchUrl&amp;nbsp;=&amp;nbsp;URL_POLLING;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;case&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;FINISHED:&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;完了画面を表示&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;dispatchUrl&amp;nbsp;=&amp;nbsp;URL_FINISH;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;request.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;DATA_KEY,&amp;nbsp;manager.getData&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;case&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ERROR:&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;エラー画面を表示&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;dispatchUrl&amp;nbsp;=&amp;nbsp;URL_ERROR;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;request.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;ERROR_KEY,&amp;nbsp;manager.getError&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;default&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;:&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throw&amp;nbsp;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;IllegalArgumentException&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;RequestDispatcher&amp;nbsp;rd&amp;nbsp;=&amp;nbsp;request.getRequestDispatcher&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;dispatchUrl&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;rd.forward&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;request,&amp;nbsp;response&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;初回に管理オブジェクトを作成し、Threadを起動。&lt;br&gt;
2回目以降は停止タイマのリセットを行い、進捗表示画面を表示。
完了、もしくはエラーだった場合はそれらの表示画面へと遷移させます。&lt;/p&gt;

&lt;h4&gt;注意点&lt;/h4&gt;

&lt;p&gt;適当にかいたソースなので同期をまじめに取っていません。
Sessionを触る際は同期を取る必要があります。2重にHTTPリクエストが飛んできた場合には
併走するThreadからセッションをいじることになるためです。&lt;/p&gt;

&lt;p&gt;ともかく、時間の掛かる処理などを裏で実行して完了時に結果を表示する場合は、こんな感じのつくりになります。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/101532.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>AOPトランザクション＋キャッシュの組み合わせは同期に気をつける</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx</link><pubDate>Sat, 06 Oct 2007 15:08:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/100259.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/06/100259.aspx#Feedback</comments><slash:comments>40</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/100259.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/100259.aspx</trackback:ping><description>&lt;p&gt;先日遭遇した深い落とし穴を紹介します。
以下のようなシステムを開発している方は同様の問題がないかチェックしてください。&lt;/p&gt;

&lt;p&gt;&lt;/ul&gt;
&lt;li&gt;AOPでトランザクションを管理している
&lt;li&gt;一部のマスタテーブルをDBから読み込んだあとシステム内でキャッシュしている
&lt;li&gt;マスタメンテナンス画面などで更新があった場合にキャッシュをクリアしている
&lt;/ul&gt;&lt;/p&gt;

&lt;h4&gt;問題となるコード&lt;/h4&gt;

&lt;p&gt;Springや、SeasarといったDIコンテナなどに付随するAOPの機能を用いてトランザクション管理していると、
DBをいじる部分のメソッド内ではcommitとかrollbackとか記述する必要がありません。
これは非常に便利で、人的なコーディングでのcommit漏れ、rollback漏れがないので
バグも入り込みにくく効率のよいものです。&lt;/p&gt;

&lt;p&gt;私のやっているプロジェクトではSpringframeworkのAOPの機能を用いてトランザクション管理を行っています。&lt;/p&gt;

&lt;p&gt;そして、システム内でよく使われ、更新頻度の低いUserテーブルは、DBアクセスのオーバーヘッドを軽減するために
システム内でキャッシュしているのです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ユーザのキャッシュ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Map&amp;lt;Integer,&amp;nbsp;User&amp;gt;&amp;nbsp;cache;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;ユーザ取得処理&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;User&amp;nbsp;getUser&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;キャッシュにあればキャッシュされたUserを返す&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.containsKey&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;))&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.get&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;なければDBから読み込む&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.userDao.getUser&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;キャッシュの削除処理&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;clearCache&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.cache.remove&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;userId&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;キャッシュの実装は上記のようなもので、内部で同期をとってあります。&lt;br&gt;
そして、UserのUPDATE処理では&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;update&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;User&amp;nbsp;user&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;UPDATE&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.userDao.update&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;user&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;キャッシュから更新対象のUserを削除&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;次回Userを取得しようとした時にキャッシュに最新のUserが読み込まれる&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;clearCache&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;user.getUserId&lt;/font&gt;&lt;font color="#000000"&gt;())&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;といった作りにしていたのです。このupdateメソッドに対してAOPでトランザクションがかけられるわけですね。&lt;/p&gt;

&lt;h4&gt;Commit前、キャッシュクリア後の魔&lt;/h4&gt;

&lt;p&gt;前置きが長くなりました。問題が発生するのはこのupdateの際のキャッシュのクリアの後です。&lt;/p&gt;

&lt;p&gt;並列して走っているスレッドがあり、update後のキャッシュクリア後、しかしDBのcommitが完了する前のタイミングで
getUser()してしまったのです。&lt;br&gt;
すると、DBはcommitされる前ですから、更新前のUser情報が読み込まれ、キャッシュには古い情報が残り続けるというわけ。&lt;/p&gt;

&lt;p&gt;DBのトランザクションとキャッシュクリアは不可分に行わなければならないのです。&lt;br&gt;
しかし、AOPでトランザクションを管理している場合、メソッド境界を跨ぐことになるので
synchronized文で容易にくくってやることができない…。&lt;/p&gt;

&lt;p&gt;わざわざキャッシュ管理している場所だけ特殊なトランザクション処理を別途書いてAOPを適用してやる必要が出てきてしまいました。&lt;br&gt;
似たようなシステム構成をしている方、潜在的なバグを孕んでいる可能性があります。早急にチェックするほうがよいでしょう。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/100259.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>セッションを扱う際には同期を意識する</title><link>http://blogs.wankuma.com/nagise/archive/2007/10/04/99731.aspx</link><pubDate>Thu, 04 Oct 2007 13:53:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/10/04/99731.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/99731.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/10/04/99731.aspx#Feedback</comments><slash:comments>68</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/99731.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/99731.aspx</trackback:ping><description>&lt;p&gt;J2EEでのWebアプリケーション開発では、簡素なルールを守りさえすればそれほど同期処理を考える必要はありません。&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;
&lt;li&gt;各クラスにstaticな可変のフィールドを作らない
&lt;li&gt;Servletの実装クラスにインスタンスフィールドを作らない
&lt;li&gt;セッションを用いない
&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;概ね、上記を守っていれば複数のユーザが並列にHTTPリクエストを投げたところで同期に起因するバグは発生しない。
DBへのアクセスは当然ながらDB側でトランザクション管理されているものとします。&lt;/p&gt;

&lt;h4&gt;セッションには同期が必要&lt;/h4&gt;

&lt;p&gt;さて本題のセッションですが、こいつを使う場合、並列してHTTPリクエストが送られてきた場合を想定する必要があります。
セッションは同一ユーザからのアクセスで同じものが参照できるわけですから、ユーザがブラウザから複数のHTTPリクエストを
発すると複数のスレッドから同時にセッションが参照されることになります。&lt;/p&gt;

&lt;p&gt;そうなると、スレッドを扱う際の問題と同じことがおきます。
例えば以下のコード、セッションからキー"test"で値をとってきて、+1して格納しなおすだけですが、&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#000000"&gt;HttpSession&amp;nbsp;session&amp;nbsp;=&amp;nbsp;request.getSession&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;Integer&amp;nbsp;i&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Integer&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;session.getAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;test&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;(A)&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;i&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Integer&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;i.intValue&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;+&amp;nbsp;&lt;/font&gt;&lt;font color="#990000"&gt;1&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;(B)&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;session.setAttribute&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#2a00ff"&gt;&amp;#34;test&amp;#34;&lt;/font&gt;&lt;font color="#000000"&gt;,&amp;nbsp;i&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#000000"&gt;;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;(C)&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ふたつのリクエスト(以下ではR1、R2と呼びます)から、ソースのA、B、Cが&lt;/p&gt;

&lt;p&gt;&lt;table&gt;
&lt;tr&gt;
  &lt;th&gt;R1&lt;/th&gt;
  &lt;th&gt;R2&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;(A)&lt;/td&gt;
  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;↓&lt;/td&gt;
  &lt;td&gt;(A)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;(B)&lt;/td&gt;
  &lt;td&gt;↓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;↓&lt;/td&gt;
  &lt;td&gt;(B)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;(C)&lt;/td&gt;
  &lt;td&gt;↓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;td&gt;(C)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/p&gt;

&lt;p&gt;というタイミングで動くと、元もとセッションに値"1"が格納されていたとしても、
2つのリクエストでそれぞれ+1されて"3"となると思いきや、"2"という値が格納されることになります。&lt;/p&gt;
&lt;p&gt;R1の(A)で"1"を読み出し、R2の(A)でも"1"が読み出されるのです。
そして、R1の(C)で"2"を書き込み、R2の(C)でも"2"を書き込む&amp;#8230;。&lt;/p&gt;

&lt;p&gt;上記は簡単な例ですが、セッションに格納した情報をいじるというのは実は大変難しいことなのです。&lt;/p&gt;

&lt;h4&gt;対策&lt;/h4&gt;

&lt;p&gt;対策としては並列処理のプログラミングの知恵をそのまま生かすことができます。&lt;/p&gt;

&lt;p&gt;セッションからの読み出しから書き込みまでをsynchronizedキーワードによって同期する方法で防ぐことができます。
しかし、同期すると同時にひとつの処理しかできないわけですから重たい処理をロックするとHTTPリクエストが
大渋滞を起こしてしまうことがあります。リロードボタンでDoSアタックができてしまうようでは困りますね。&lt;/p&gt;

&lt;p&gt;ロックを行わない同期としては&lt;a href="http://ja.wikipedia.org/wiki/Lock-free%E3%81%A8Wait-free%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0"&gt;コンペア・アンド・スワップ&lt;/a&gt;などの手法があります。
楽観排他などとイメージは似ていますね。書き込み段階で読み出した値と違っていないかを確認することで、
途中で書き換えられていた場合にエラーで落とすことが出来ます。&lt;/p&gt;

&lt;p&gt;この先はもう並列処理の話になってしまうので本稿では割愛しますが、
セッションを扱う際には同期を意識する必要があることは心にとどめ置いてください。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/99731.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>サーバサイドJavaでのメモリ上限</title><link>http://blogs.wankuma.com/nagise/archive/2007/09/20/97197.aspx</link><pubDate>Thu, 20 Sep 2007 16:26:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/09/20/97197.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/97197.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/09/20/97197.aspx#Feedback</comments><slash:comments>1004</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/97197.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/97197.aspx</trackback:ping><description>&lt;P&gt;Programming SHOT BARへようこそ。本日はVMの管理するメモリの話です。メモリリークによるOutOfMemoryの話ではありません。&lt;/P&gt;
&lt;H4&gt;VMが扱えるメモリの上限&lt;/H4&gt;
&lt;P&gt;一般的な&lt;strong&gt;32bitのJavaVM&lt;/strong&gt;が管理できるメモリの&lt;strong&gt;上限は1.7G程度&lt;/strong&gt;です。 JavaのVM自体はOSから見れば単一アプリケーションにすぎません。 Javaのアプリケーション内でのメモリ確保は、&lt;strong&gt;VMが確保したメモリが分配されている&lt;/strong&gt;わけです。ですから、OS上からJavaVMが確保しているメモリを見てもVM内でどれだけのメモリが利用されているかはわかりません。&lt;/P&gt;
&lt;P&gt;これはわりと嵌る人が多いように思います。少なくとも過去にBBSで2度以上見た覚えがあります。 Javaでもメモリ使用量を観測しようとした場合、Windowsの&lt;strong&gt;タスクマネージャでJavaVMが使用しているメモリを見てもあまり意味がありません&lt;/strong&gt;。これはVMが確保しているメモリ総量よりは大きい値になりますが、確保した領域中、どれだけが空きメモリなのかはわからないのです。それはOSの知るところではなく、JavaVMの管理下にある情報なのです。 JavaVM内での&lt;strong&gt;空きメモリは &lt;A href="http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/Runtime.html#freeMemory()"&gt;java.lang.Runtime#freeMemory()&lt;/A&gt;で参照&lt;/strong&gt;できます。また&lt;strong&gt;&lt;A href="http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/management/jconsole.html"&gt;jconsole&lt;/A&gt; によって外から接続してメモリ使用状況を確認する&lt;/strong&gt;ことも出来ます。&lt;/P&gt;
&lt;P&gt;JavaVMが確保するメモリの上限は実行時のオプションで設定できます。 &lt;A href="http://java.sun.com/javase/ja/6/docs/ja/technotes/tools/windows/java.html"&gt;javaコマンドのリファレンス&lt;/A&gt;で説明されていますが、オプション&lt;strong&gt;-Xmxで上限設定&lt;/strong&gt;をすることができます。しかし、上限はVMの実装によるため、ここでは設定できる上限値についての情報は記述されていません。 VMの実装によっては2Gを超えるヒープ領域が扱える&lt;strong&gt;"Large Heap"&lt;/strong&gt;と呼ばれる機能を備えているものもあるようです。&lt;/P&gt;
&lt;P&gt;Javaアプリケーションの稼動するサーバを構築した場合、 JavaVM自体はVMの本体も含め2G程度のメモリしか消費しません。それを超える&lt;strong&gt;物理メモリを乗せていても活用できない&lt;/strong&gt;場合があります。&lt;strong&gt;サーバサイドで動かすのであれば64bit版のVMを使いたい&lt;/strong&gt;ところです。&lt;/P&gt;
&lt;P&gt;たとえ64bit版を使っていたとしても&lt;strong&gt;物理メモリを超える容量を設定してはいけません&lt;/strong&gt;。 OSが仮想メモリをサポートしているでしょうから止まるということは無いにしても、&lt;strong&gt;深刻なパフォーマンスの劣化をもたらす&lt;/strong&gt;場合があります。&lt;BR&gt;VMは該当オブジェクトが配されているメモリがスワップされた領域なのか、そうでないのかを管理するわけではありませんから、多量のスワップが発生することがあります。&lt;/P&gt;
&lt;P&gt;そのような事情から、Javaのアプリケーションで使用できる&lt;strong&gt;メモリの上限はおのずと制限されます&lt;/strong&gt;。&lt;/P&gt;
&lt;H4&gt;上限を振り切る可能性&lt;/H4&gt;
&lt;P&gt;サーバサイドでの処理は時にヘビィで、瞬間的に大量のメモリを消耗することがあります。 Excelファイルを生成する&lt;A ? poi.apache.org href-?http:&gt;Apache POI&lt;/A&gt;などはその典型で、非常に多くのメモリを消耗します。サーバサイドでは並列にユーザからリクエストを受けるのが通常ですから、この&lt;strong&gt;メモリを食う処理が多重に動いた場合、メモリ上限を超え、OutOfMemoryとなることがあります&lt;/strong&gt;。&lt;/P&gt;
&lt;P&gt;これはメモリリークではないため、抜本的な対応は難しいのですが、&lt;strong&gt;VM内で片付けるなら Worker Threadパターン&lt;/strong&gt;(&lt;A href="http://www.amazon.co.jp/dp/4797331623"&gt; 増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編&lt;/A&gt;の8章参照)を利用します。作業用のThread本数を制限し、同時に多量に並列起動しないようにするわけです。 JavaSE5.0以降であればjava.util.concurrent.ThreadPoolExecutorを使うことで比較的容易に対応できます。&lt;/P&gt;
&lt;P&gt;しかし、いずれにせよデータ量で使用メモリが変動しますから、正確な上限がつかめるわけではありません。いっそ、&lt;strong&gt;POIによるExcel生成を別VMに分けてしまって、VM間で受け渡しするようなシステム構成&lt;/strong&gt;を考えたほうがよいのではないでしょうか。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/97197.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>スレッドのキャンセル</title><link>http://blogs.wankuma.com/nagise/archive/2007/08/28/92416.aspx</link><pubDate>Tue, 28 Aug 2007 20:28:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/08/28/92416.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/92416.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/08/28/92416.aspx#Feedback</comments><slash:comments>42</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/92416.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/92416.aspx</trackback:ping><description>&lt;p&gt;Programming SHOT BARへようこそ。
ここのところマルチスレッド関連の話題で盛り上がっています。
今日はかつのりさまからのリクエストでスレッドのキャンセルにまつわる話です。&lt;/p&gt;

&lt;h4&gt;参考資料&lt;/h4&gt;

&lt;p&gt;以下の書籍を参考にしています。手元にある方は参照してみてください。&lt;/p&gt;
&lt;p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.amazon.co.jp/dp/4894717166/"&gt;プログラミング言語Java第4版&lt;/a&gt; 14.8.1 スレッドのキャンセル 318p&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.co.jp/dp/4797337206/"&gt;Java並行処理プログラミング&lt;/a&gt; 7-1 タスクのキャンセル 154p&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.co.jp/dp/4797331623/"&gt;増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編&lt;/a&gt; 補講1 例外InterruptedExceptionを理解する 179p&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.co.jp/dp/477411491X/"&gt;Javaスレッド完全制覇&lt;/a&gt; 4.2 割り込み 102p&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;

&lt;h4&gt;Thread#stop()とその問題点&lt;/h4&gt;

&lt;p&gt;Thread#stop()、Thread#suspend()、Thread#resume()という一連のスレッドの停止・再開メソッドは
&lt;strong&gt;非推奨メソッドなっており、使用してはいけません&lt;/strong&gt;。&lt;br&gt;
この件については、sunからわざわざ詳細な説明がアナウンスされています。
&lt;a href="http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/misc/threadPrimitiveDeprecation.html"&gt;
http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/misc/threadPrimitiveDeprecation.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;スレッドは外部から強制的に、しかし、安全に停止させることはできません。
なんらかの処理をしている最中に安全に中断するということは本質的に難しいのです。&lt;br&gt;
その状況によって後始末を必要とします。
停止の要求に対して、「ちょっとまって。今中断するから」といった協力なしには安全な停止はなしえません。&lt;/p&gt;

&lt;h4&gt;フラグを立ててスレッドを停止させる&lt;/h4&gt;

&lt;p&gt;スレッドに対し、&lt;strong&gt;割り込みフラグを用意することで自発的な停止をさせる&lt;/strong&gt;ことが出来ます。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;割り込みフラグ&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;volatile&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;boolean&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;stopFlag;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;run&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;!&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.stopFlag&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;実処理&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;上記サンプルではvolatileによってメモリ同期化されたフラグを利用して、
whileループを抜けるようにしてあります。
このように、外部からフラグを変更してやることでスレッドを自発的に停止させています。&lt;/p&gt;

&lt;p&gt;しかし、Object#wait()やObject#join()などのスレッドをブロックするメソッドを
利用している場合、フラグを判定する箇所（&lt;strong&gt;キャンセルポイント&lt;/strong&gt;といいます）まで
永遠にたどり着くことはないかもしれません。&lt;/p&gt;

&lt;p&gt;個々のプログラマが独自に定義したスレッドの割り込みフラグの限界はここにあります。
APIのような不特定多数に利用してもらう場合には、やはり標準的な仕組みが欲しいですね。&lt;/p&gt;

&lt;p&gt;Thread#interrupt()はその&lt;strong&gt;標準的なスレッドの割り込みフラグ&lt;/strong&gt;なのです。&lt;/p&gt;

&lt;h4&gt;Thread#interrupt()&lt;/h4&gt;

&lt;p&gt;Thread#interrupt()はThread標準で提供される停止フラグの通知機構です。
この呼び出しで対象のスレッドに対して割り込みフラグが立ちます。&lt;br&gt;
この割り込みフラグはThread#isInterrupt()によって参照することができます。
staticなメソッドThread#interrupted()を使うと、現在のスレッドの割り込みフラグを
参照した上でフラグをリセットすることが出来ます。詳しくはjavadocを参照してください。&lt;/p&gt;

&lt;p&gt;Object#wait()はThread#interrupt()によってスレッドの停止フラグが立つと、
waitすることを止めて、InterruptedExceptionをthrowします。&lt;br&gt;
waitに限らず、ブロックされるメソッドは、基本的にスレッド停止フラグが立つと
InterruptedExceptionをthrowする作りになっています。&lt;/p&gt;

&lt;p&gt;また、先のサンプルのように、ブロックされないスレッドにおいては、Thread#interrupt()を
利用しなくてもスレッドの停止を行うことが出来ます。&lt;/p&gt;

&lt;p&gt;では、我々プログラマが独自に作成したスレッドではこの
どのような対処をする必要があるのでしょうか？&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;
&lt;li&gt;InterruptedExceptionをthrowするように作る&lt;/li&gt;
&lt;li&gt;Thread#interrupt()で立てられた割り込みフラグを維持し、どこかのキャンセルポイントまで流す&lt;/li&gt;
&lt;li&gt;自力でキャンセル処理をし、スレッドを終了させる&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;という３つの選択肢があります。
スレッドから呼び出される想定のメソッドで、処理が長引くことが想定される場合は
InterruptedExceptionをthrowする作りにしておくとよいでしょう。
例えば集計処理などの時間が掛かる処理ですね。&lt;br&gt;
そもそも、そんなに時間の掛からない処理であれば、キャンセルポイントを作る必要もありません。
フラグに触らずそのまま処理を終えてどこかのキャンセルポイントにお任せします。&lt;br&gt;
Thread#run()のような場所ではExceptionをthrowsするように宣言できませんから、
こういう箇所では自力でキャンセルポイントを実装してやります。&lt;/p&gt;

&lt;p&gt;あらかじめThread#interrupt()による割り込みをチェックして
中断させるキャンセルポイントを作っておくことで、無駄な処理を続けることなく
速やかに停止させることが出来ます。
せっかちな現代人には必須の機能かもしれませんね。&lt;/p&gt;

&lt;h4&gt;業務での応用&lt;/h4&gt;

&lt;p&gt;集計処理など時間が掛かることが想定されるメソッドは、Thread#interrupt()による
停止をサポートしておくと、途中キャンセルされた場合に処理を止めることで
CPUリソースを無駄に食わずに済みます。&lt;/p&gt;

&lt;p&gt;java.nio.channels.InterruptibleChannelによる通信であれば、
通信に割り込んで停止させることも可能です。&lt;/p&gt;

&lt;p&gt;このあたり、業務要件で顧客から直接要望されることは少ないでしょうが、
パフォーマンスにこだわりがあるお客さん相手なら、
設計段階から中断についても考慮しておくと良いかもしれません。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/92416.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>スレッドから値を返すには - その２</title><link>http://blogs.wankuma.com/nagise/archive/2007/08/27/92177.aspx</link><pubDate>Mon, 27 Aug 2007 21:12:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/08/27/92177.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/92177.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/08/27/92177.aspx#Feedback</comments><slash:comments>107</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/92177.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/92177.aspx</trackback:ping><description>&lt;p&gt;&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/08/21/91284.aspx"&gt;前回&lt;/a&gt;
から別の方向に大きく逸れてしまいましたが、別スレッドでの結果を取得する第２回です。&lt;/p&gt;

&lt;p&gt;下記コードはThread.join()を使って他のスレッドの終わりを待って値を取得しようというサンプルです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;joinを用いて他のThreadの結果を取得するサンプル。&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;同期が行われていないので潜在的な危険を孕んでいる？&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;JoinTest&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;extends&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Thread&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;return用の値&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;value;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&amp;nbsp;Threadでの処理&amp;nbsp;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#646464"&gt;@Override&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;run&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;実処理&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;...&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.value&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#990000"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;/**&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*&amp;nbsp;値取得用のメソッド。&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f5fbf"&gt;*/&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;getValue&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.value;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;void&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;main&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;String&lt;/font&gt;&lt;font color="#000000"&gt;[]&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;args&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;throws&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Exception&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;JoinTest&amp;nbsp;t&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;JoinTest&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;t.start&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;Threadの終了を待つ&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;t.join&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;結果の取得&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;int&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;ret&amp;nbsp;=&amp;nbsp;t.getValue&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;私の理解が正しければ、このコードは正しい値を返さない可能性があるのではないでしょうか？&lt;/p&gt;

&lt;h4&gt;double-checked locking問題と同じ？&lt;/h4&gt;

&lt;p&gt;どうにもこのコード、
&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/08/24/91598.aspx"&gt;double-checked locking問題&lt;/a&gt;
と同じ匂いがするのです。&lt;/p&gt;

&lt;p&gt;Thread.join()による待機の完了は、対象スレッドのどの処理よりも後となることは保証されています。
では、上記サンプルのように対象スレッド内でフィールドに書き出しておいて、
join()で終わりを待って値を読み込めば正しく値が読み出せるように思えます。&lt;/p&gt;

&lt;p&gt;ところが、Thread.join()は同期されるわけではないので、この時点でメモリが同期されていることを
期待してはいけないのではないでしょうか？&lt;/p&gt;

&lt;p&gt;受け渡し用のフィールドがvolatileでありさえすれば、問題は起こらないことでしょう。
しかし非volatileでかつ非synchronizedの場合は&amp;#8230;？&lt;/p&gt;

&lt;h4&gt;クラス設計上の問題&lt;/h4&gt;

&lt;p&gt;wait()方式に比べた弱点は、クラスとして完結させにくい点です。&lt;/p&gt;

&lt;p&gt;少なくとも、Thread#start()の後にThread#join()して、それから値を取得してくださいね、
なんて約束をクラスの利用者に守ってもらうというのは防衛的ではないですよね。&lt;/p&gt;

&lt;p&gt;防衛的なクラス設計にするのであれば、getValue()メソッドの内部で完了を待機したいところです。
そうなると、Thread#join()を実行するために、自身が実行されているThreadのインスタンスが必要となります。
結局、Thread.start()までをもクラス内部に抱え込まないと安全で利便性の高いクラスにはできません&amp;#8230;。&lt;/p&gt;

&lt;p&gt;このように、クラス設計において、wait()方式に比べると若干面倒が多いように思えます。&lt;br&gt;
InterruptedExceptionへの対応が必要な点や、同期が必要な点はwait()と変わりませんから
メリットは特に無いのではないでしょうか。Threadはリソースも多く食いますしね。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/92177.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>double-checked-locking問題のまとめ</title><link>http://blogs.wankuma.com/nagise/archive/2007/08/24/91598.aspx</link><pubDate>Fri, 24 Aug 2007 09:52:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/08/24/91598.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/91598.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/08/24/91598.aspx#Feedback</comments><slash:comments>412</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/91598.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/91598.aspx</trackback:ping><description>&lt;p&gt;&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/08/21/91284.aspx"&gt;先のエントリ&lt;/a&gt;で
もりあがったdouble-checked-locking問題についてのまとめです。&lt;/p&gt;
&lt;h4&gt;参考資料&lt;/h4&gt;
&lt;p&gt;IBMの記事が質が高くて分かりやすいですね。&lt;/p&gt;
&lt;p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www-06.ibm.com/jp/developerworks/java/020726/j_j-dcl.html"&gt;double-checked lockingとSingletonパターン&lt;/a&gt;(2002年5月)
&lt;li&gt;&lt;a href="http://www-06.ibm.com/jp/developerworks/java/040416/j_j-jtp02244.html"&gt;Javaの理論と実戦: Javaメモリ・モデルを修正する　第1回&lt;/a&gt;(2004年2月24日)
&lt;li&gt;&lt;a href="http://www-06.ibm.com/jp/developerworks/java/040514/j_j-jtp03304.html"&gt;Javaの理論と実戦: Javaメモリ・モデルを修正する　第2回&lt;/a&gt;(2004年3月30日)
&lt;li&gt;&lt;a href="http://www.javareading.com/bof/cookbook-J20060917.html"&gt;コンパイラ開発者のためのJSR133クックブック&lt;/a&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;h4&gt;double-checked locking問題とは&lt;/h4&gt;
&lt;p&gt;「double-checked lockingとSingletonパターン」では、GoFデザインパターンのSingletonパターンを
Javaで実装する際に同期の処理コストも含め、どのようにすべきかについて書かれています。&lt;/p&gt;
&lt;p&gt;「double-checked locking」と呼ばれるアルゴリズムは、下記のようなコードです。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;class&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Singleton&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;private&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Singleton&amp;nbsp;instance;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;public&amp;nbsp;static&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Singleton&amp;nbsp;getInstance&lt;/font&gt;&lt;font color="#000000"&gt;()&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;instance&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;Singleton.&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;instance&amp;nbsp;==&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;null&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;instance&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Singleton&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;instance;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;このコードは、同期による処理コストも少なく、かつ正しく同期され、Singletonが実装されているように見えます。&lt;/p&gt;
&lt;p&gt;しかし、思いもよらない問題が顔を出します。
&lt;strong&gt;このgetInstance()返されるインスタンスはnullではないにも関わらず、
コンストラクタによる初期化が終わっていない可能性がある&lt;/strong&gt;、という話です。&lt;/p&gt;
&lt;p&gt;べつに同期自体がうまくいかず、複数回インスタンスが生成されるというわけではありません。
メモリを確保し、参照が作られ、その後にコンストラクタが動く、
その流れのなかで、コンストラクタが動く前に参照がreturnされることがある、
ということをIBMの記事では解説しています。&lt;/p&gt;
&lt;p&gt;先のエントリのコメントでは、この参照は作られたが初期化がされていないタイミングを逢魔が刻とたとえたのでした。&lt;/p&gt;
&lt;p&gt;これは、最適化などのために処理が変わらない範囲での順序の変更が許されているという
VM実装の事情によるもののようです。
これがメモリの同期と絡まって出てきた逢魔が刻こそが
double-checked locking問題ということになります。&lt;/p&gt;
&lt;h4&gt;JSR 133&lt;/h4&gt;
&lt;p&gt;Javaの仕様はJCP(Java Community Process)という機関で決められます。&lt;br&gt;
ここで議論される要求がJSR(Java Specification Reqest)です。このあたりのプロセスは
&lt;a href="http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20040707/146933/"&gt;Javaの開発者は，ちょっと&amp;#8220;うるさい&amp;#8221;&lt;/a&gt;
という記事が分かりやすいかと思います。&lt;/p&gt;
&lt;p&gt;JSR 133はJavaのメモリモデルに対する仕様変更要求です。
「コンパイラ開発者のためのJSR133クックブック」がこのJSR 133について詳しく解説しています。
今回参考資料に挙げたリンクは原文と日本語との対訳で書かれているので読みやすいと思います。&lt;/p&gt;
&lt;p&gt;このJSR 133はJavaSE 5.0から搭載されています。&lt;/p&gt;
&lt;h4&gt;問題は解決するのか？&lt;/h4&gt;
&lt;p&gt;JSR 133によって、&lt;strong&gt;volatileなフィールドに関しては、
参照は作られたが初期化がされていない逢魔が刻は存在しない&lt;/strong&gt;ようです。&lt;br&gt;
この点についてはIBMの記事に解説があるので、ちょっと長いですが引用します。&lt;/p&gt;
&lt;p&gt;&lt;blockquote&gt;
これはdouble-checked locking問題を解決するのか？&lt;br&gt;
&lt;br&gt;
double-checked locking問題に対して提案されている解決方法の一つは遅延初期化されたインスタンス（lazily initialized instance）を保持するフィールドをvolatileフィールドにするというものです。（double-checked locking問題と、その解決方法として提案されたアルゴリズム的な方法ではなぜうまく行かないかの説明については参考文献を見てください。）古いメモリ・モデルの下では、これではdouble-checked lockingをスレッド・セーフにしませんでした。その理由はvolatileフィールドへの書き込みは、他の非volatileフィールド（例えば新しくコンストラクトされたオブジェクトのフィールドなど）への書き込みで、やはりリオーダーでき、そのためvolatileインスタンス参照は、不完全にコンストラクトされたオブジェクトへの参照をやはり保持できたためです。&lt;br&gt;
&lt;br&gt;
新しいメモリ・モデルの下では、double-checked lockingに対するこの「解決方法」で表現法（idiom）がスレッド・セーフになるのです。それにもかかわらず、まだこの表現法を使うべきではないのです！ Double-checked lockingの要点は、ごく初期のJDKでは同期化が比較的高価だったという大きな理由から、共通コード・パスの同期化を不要にするために考えられた、パフォーマンス最適化のはずだった、ということなのです。その後、非競合同期化（uncontended synchronization）はずっと安価になったのですが、volatileの意味体系に加えられた新しい変更によって、一部のプラットフォームでは古い意味体系よりも比較的高価になってしまったのです。（実質的には、volatileフィールドへの各読み書きはちょうど、「半」同期化のようなものです。つまりvolatileの読み込みはモニターが取得するのと同じメモリ意味体系を持ち、volatileへの書き込みはモニターが解放するのと同じ意味体系を持っているのです。）ですから、double-checked lockingの目標が、より単純な、同期化による手法よりも改善されたパフォーマンスを得る事だとすると、この「修正版」解決方法もあまり役には立たちません。
&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;このように、volatileである場合はスレッドセーフになりうると書かれています。&lt;br&gt;
ではなぜ、単なるdouble-checked lockingでは駄目なのでしょう？
メモリモデルが変更になったのだから、synchronizedでちゃんと同期してくれるようになったんじゃないの？&lt;br&gt;
私の理解では、volatileでもsynchronizedでも、メモリの同期は行われるわけですが、
volatileフィールドへの代入に際しては最適化のための順序置き換えが禁止されるため、
逢魔が刻を回避できる、単なるsynchronizedによるメモリ同期ではそれを回避できない、という解釈です。&lt;br&gt;
このあたりの結論は自信がないので、是非、コメントで突っ込みを入れてください。&lt;/p&gt;
&lt;h4&gt;結論&lt;/h4&gt;
&lt;p&gt;結局のところ、JavaSE 5.0だとしても、冒頭に掲げたサンプルコードでは初期化されていない
参照が返される可能性があるということになるのではないでしょうか。&lt;/p&gt;
&lt;p&gt;volatileフィールドを利用することで回避することはできるのでしょうが、
同期のコストを回避するというdouble-checked lockingの本来の目的は達成できない、
という結論となるようです。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/91598.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>凪瀬</dc:creator><title>waitについてのまとめ</title><link>http://blogs.wankuma.com/nagise/archive/2007/08/22/91406.aspx</link><pubDate>Wed, 22 Aug 2007 11:46:00 GMT</pubDate><guid>http://blogs.wankuma.com/nagise/archive/2007/08/22/91406.aspx</guid><wfw:comment>http://blogs.wankuma.com/nagise/comments/91406.aspx</wfw:comment><comments>http://blogs.wankuma.com/nagise/archive/2007/08/22/91406.aspx#Feedback</comments><slash:comments>239</slash:comments><wfw:commentRss>http://blogs.wankuma.com/nagise/comments/commentRss/91406.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/nagise/services/trackbacks/91406.aspx</trackback:ping><description>&lt;p&gt;&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/08/21/91284.aspx"&gt;並列処理&lt;/a&gt;
でえらく盛り上がってしまったので一旦まとめたいと思います。&lt;br&gt;
こちらのエントリではObject#wait()についてのまとめです。&lt;/p&gt;

&lt;h4&gt;waitの使い方&lt;/h4&gt;

&lt;p&gt;Object#wait()を呼び出すことで現在のThreadを停止させることが出来ますが、
この際のObjectのインスタンスは
&lt;A href="http://blogs.wankuma.com/nagise/archive/2007/08/22/91364.aspx"&gt;Javaの並列処理の基本&lt;/a&gt;
の稿で説明したロックオブジェクトを用います。&lt;/p&gt;

&lt;p&gt;wait()を呼び出す前に、対象となるオブジェクトをロックオブジェクトとして
&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&lt;/b&gt;&lt;/font&gt;ブロックを作らねばなりません。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;Object&amp;nbsp;lock&amp;nbsp;=&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;Object&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ロックオブジェクトでsynchronizedブロックを作る&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;lock&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;ロックオブジェクトのwait()を呼び出す&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;lock.wait&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&lt;/b&gt;&lt;/font&gt;ブロックの外でwait()を呼んだ場合は
IllegalMonitorStateExceptionが&lt;font color="#7f0055"&gt;&lt;b&gt;throw&lt;/b&gt;&lt;/font&gt;されます。&lt;/p&gt;

&lt;p&gt;Object#notify()およびObject#notifyAll()でwait()しているスレッドは動き出します。
このnotifyのインスタンスはもちろん、waitするときに利用したロックオブジェクトです。&lt;br&gt;
notify()もまた、自身をロックオブジェクトとした&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&lt;/b&gt;&lt;/font&gt;ブロック内で
呼び出さないとIllegalMonitorStateExceptionを&lt;font color="#7f0055"&gt;&lt;b&gt;throw&lt;/b&gt;&lt;/font&gt;します。&lt;br&gt;
ロックオブジェクトをうまく管理すれば、停止再開を行う箇所をグルーピングできるわけです。&lt;/p&gt;

&lt;h4&gt;spurious wakeup&lt;/h4&gt;

&lt;p&gt;スプリアス・ウェイクアップと呼ばれる現象が知られています。
本来起きるべきではないタイミングでwait()から目覚めることがある、という現象です。&lt;/p&gt;
&lt;p&gt;この現象については
&lt;a href="http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/Object.html#wait(long)"&gt;
Object#wait()のjavadoc&lt;/a&gt;にも記載があります。&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;

スレッドは、通知、割り込み、タイムアウトなしに再開されることがあります。 これは、「スプリアスウェイクアップ」と呼ばれています。スプリアスウェイクアップは、実際にはまれにしか発生しませんが、アプリケーションでは、スレッドが再開されることで発生する可能性がある条件をテストし、条件が満たされない場合は待機を続けて、スプリアスウェイクアップから保護しなければなりません。つまり、次のようにループで常に待機が発生するようにする必要があります。 &lt;br&gt;
&lt;br&gt;
synchronized (obj) {&lt;br&gt;
while (&lt;condition does not hold&gt;)&lt;br&gt;
obj.wait(timeout);&lt;br&gt;
... // Perform action appropriate to condition&lt;br&gt;
     }&lt;br&gt;
 &lt;br&gt;
(このトピックの詳細は、Doug Lea 著『Concurrent Programming in Java (Second Edition)』(Addison-Wesley, 2000) のセクション 3.2.3 や Joshua Bloch 著『Effective Java Programming Language Guide』(Addison-Wesley, 2001) のアイテム 50 を参照してください)。 
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;ここで引き合いに出されている&lt;a href="http://www.amazon.co.jp/dp/4894714361"&gt;Effective Java&lt;/a&gt;では&lt;p&gt;

&lt;p&gt;&lt;blockquote&gt;
待ちスレッドは、通知がなくても起きるかもしれません。これは、&lt;b&gt;偽りの目覚め&lt;/b&gt;(&lt;i&gt;sputious wakeup&lt;/i&gt;)と呼ばれます。『Java 言語仕様』[JLS]がその可能性について述べていないにもかかわらず、多くのJVM実装は、たとえ稀であるにせよ、偽りの目覚めが起きることが知られているスレッド機構を使用しています[Posix, 11.4.3.6.1]。
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;と記述されています。([]の記述は参考文献)&lt;/p&gt;
&lt;p&gt;実際、&lt;a href="http://www.amazon.co.jp/dp/4894717158"&gt;Java言語仕様(日本語版訳第3版)&lt;/a&gt;の
506ページ、「17.8待機集合と通知」にはスプリアス・ウェイクアップの記述はありません。&lt;/p&gt;

&lt;p&gt;また、&lt;a href="http://www.amazon.co.jp/dp/4797337206"&gt;Java並行処理プログラミング&lt;/a&gt;でも
337ページ、「14-2-2 早すぎるウェイト終了」にて紹介されています。（yamasaさま、情報ありがとうございます）&lt;/p&gt;

&lt;h4&gt;我々が気をつけなければならないこと&lt;/h4&gt;

&lt;p&gt;正に問題となるのは以下のようなコードです。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.lock&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;終了前ならwait&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;if&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;!&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.flag&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.lock.wait&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;値を返す&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.value;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;フラグが立っていなければwaitし、どこか別のスレッドでこのフラグが立てられ、
notifyされて動き出すことを期待しています。&lt;/p&gt;
&lt;p&gt;しかし、ここで前述のスプリアス・ウェイクアップが起きるとしたら、
まだ&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;.flagが&lt;font color="#7f0055"&gt;&lt;b&gt;false&lt;/b&gt;&lt;/font&gt;のうちに動き出し、
値を&lt;font color="#7f0055"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt;してしまう可能性があるのです！&lt;/p&gt;

&lt;p&gt;そのため、以下のように&lt;font color="#7f0055"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt;ループを用いて
不意に動き出したときの対策をしなければなりません。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;synchronized&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.lock&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;終了前ならwait&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;while&amp;nbsp;&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#000000"&gt;!&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.flag&lt;/font&gt;&lt;font color="#000000"&gt;)&amp;nbsp;{&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.lock.wait&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;/font&gt;&lt;font color="#000000"&gt;;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#3f7f5f"&gt;//&amp;nbsp;値を返す&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#7f0055"&gt;&lt;b&gt;return&amp;nbsp;this&lt;/b&gt;&lt;/font&gt;&lt;font color="#000000"&gt;.value;&lt;/font&gt;&lt;br /&gt;
&lt;font color="#ffffff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;javadocに記載されたミステリー&lt;/h4&gt;

&lt;p&gt;Object#wait()は３つのオーバーロードを持っていますが、
引数なしのオーバーロードには以下の記述があります。&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;
&lt;strong&gt;引数が 1 つのバージョンでは&lt;/strong&gt;、割り込みやスプリアスウェイクアップが発生する可能性があるので、このメソッドは常にループで使用される必要があります。
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;引数なしのwait()ではスプリアス・ウェイクアップが起きないかのような記述です。&lt;br&gt;
日本語訳の誤りかと思ったのですが、&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop: 
&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;英語版の記述が上記通りなので、翻訳の誤りではないようです。&lt;br&gt;
このあたりはEffective Javaの言うところの「偽りの目覚めが起きることが知られているスレッド機構」
とやらを調べて見ないと結論できないように思います。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/nagise/aggbug/91406.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>