デザインパターン入門 マルチスレッド編まとめ
がーっと読んだ。実際に使うときの思い出しトリガーになるようにメモしておく。
マルチスレッドプログラムの評価基準
- 安全性 オブジェクトを壊さないこと
- スレッドセーフなクラス
- 生存性 必要な処理が行われること
- 安全性を重視しただけでは生存性を下げてしまう場合がある。例えばデッドロック。
- 再利用性 クラスを再利用できること
- スレッドの排他制御の仕組みや方針をうまくクラスの中に隠蔽すれば、再利用性の高いプログラムになる。
- パフォーマンス 処理を高速・大量に行えること
安全性と生存性を守るのは必須。その上で、いかにして再利用性とパフォーマンスを上げるかが重要。
Single Thread Execution 「この橋を渡れるのは、たった一人」
- 複数のスレッドがインスタンスを共有する場合の基本パターン
- クリティカルセッション(インスタンスが不安定な状態になる範囲)をまず定める
- クリティカルセッションは1つのスレッドだけが実行するようにガードする
- Javaではsynchronizedを使って実現する
- インスタンスの状態が変化しないのであれば、Immutableパターンを使う。(スループット向上)
- インスタンスの状態を参照するスレッドと変更するスレッドが分かれているときは、Read-Write Lockパターンを使う。(スループット向上)
Immutable 「壊したくとも、壊せない」
Guarded Suspension 「用意できるまで、待っててね」
- これも頻出パターン
- インスタンスが適切な状態になるまで、ガード条件を使ってスレッドを待たせる。
- ガード条件が変化したことをスレッドの通知(notifyAll)
- ガード条件が満たされないなら待たずに帰る場合は、Balkingパターンを使う。
Balking 「必要なかったら、やめちゃおう」
- Guarded Suspensionパターンで、ガード条件が満たされない場合に待たずに帰る
Producer-Consumer 「わたしが作り、あなたが使う」
Read-Write Lock 「みんなで読んでもいいけれど、読んでる間は書いちゃダメ」
Thread-Per-Message 「この仕事やっといてね」
- スレッド(Client)がインスタンス(Host)のメソッドを呼び出している場合、メソッド処理が終了するまでHostから制御が戻ってこない。(応答性ダウン)
- Hostが処理用のスレッドを新たに起動し、処理を任せる。Clientにはすぐに応答する。(メソッドの起動とメソッドの実行の分離)
- 処理結果を戻したい場合は、Futureパターンを使う。
- スレッドを使いまわしたい場合は、Worker Threadパターンを使う。
Worker Thread 「仕事が来るまで待ち、仕事が来たら働く」
Future 「引換券をお先にどうぞ」
Two-Phase Termination 「後片付けしてから、おやすみなさい」
- 動作しているスレッドを安全に終了させたいときに利用できるパターン
- 終了処理を行うタイミングは終了するスレッド本人に判断させる
- スレッドを終了させるために「終了要求」用のメソッドを用意
- 終了要求を受けたスレッドは、安全に終了処理を実行できるタイミングで終了処理を開始する
Thread-Specific Storage 「スレッドごとのコインロッカー」
- シングルスレッドの環境で動作することを想定しているオブジェクトを、マルチスレッド環境で利用したいときに使うパターン。
- スレッドごとにデータを格納したい場合に使うパターン
- JavaではThreadLocalクラスで実現できる
Active Object 「非同期メッセージを受け取る、能動的なオブジェクト」
- シングルスレッドで動作することを前提として設計されているServant役に皮をかぶせて、マルチスレッドのClient役から利用できるようにするパターン。
- Servantを呼び出すScheduler役のスレッドを導入。Workerスレッドが1個のWorker Threadパターン。これで複数のClientが処理できる。
- Clientからの要求はProxyへのメソッド呼び出しとして実現。Proxyで要求を1つのオブジェクトに変換し、Producer-Consumerパターンを使ってSchedulerに渡す。(Clientへの応答性の確保)
- 実行すべき要求の選出はSchedulerが行う。
- 実行結果はFutureパターンを使ってClientへ返す。
【付録】Javaのメモリモデル
- Javaのメモリモデルには、「メインメモリ」と「ワーキングメモリ」がある。
- メインメモリはインスタンスが存在する領域。個々のスレッドはメインメモリには直接アクセスできない。
- ワーキングメモリは個々のスレッドが持っている作業領域。必要に応じて、メインメモリからワーキングメモリ(またはその逆)にコピーが行われる。
- 各スレッドは常にメインメモリにある最新の状態を参照できるとは限らない。(仕様上)
- synchronizedの2つの働き
- スレッドの同期
- メモリの同期。ワーキングメモリとメインメモリの内容の同期が取られる。(ただしsynchonizedに入るときのみ)
- volatileの2つの働き
- メモリの同期
- long、doubleの代入をアトミックに行う。
Resizableの使い方
基本的な使い方のメモ。
// target_idはDOMエレメントのID // 例えば、<div id="target_id">ここがリサイズされる</div> // var elm = new Ext.Resizable('target_id', { width: 200, height: 50, minWidth: 0, maxWidth: 500, handles: 'e', // 右方向だけリサイズ可 dynamic: true, transparent: true // リサイズ時に枠を表示しない }); // リサイズ時のイベント処理 elm.on("resize", function() { // リサイズ後の幅を取得 alert(this.getEl().getWidth()); });
参考
Ext.JS 公式サイトデモページ http://extjs.com/deploy/dev/examples/resizable/basic.html
Windowの下までスクロールされたことを検出する
AutoPagerizeのようなことを実現するために、Windowの下までスクロールされたことを検出するJavaScriptを調べてみた。
意外と苦労したのでメモ。
ソース
// 垂直スクロール量を取得する var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; // 表示領域の高さを取得する var clientHeight = document.body.clientHeight; // スクロールバーで隠れた領域を含むコンテンツ領域の高さを取得する var scrollHeight = document.body.scrollHeight; // コンテンツ領域の底までの残り領域 var remain = scrollHeight - clientHeight - scrollTop;
Firefox2、IE6で動作確認。このコードではOperaやSafariではもしかしたら動かないかも。(下の参考記事を参照)
スクロールバーを一番下まで下げた場合、IE6だとremainは0になるが、Firefox2では1となった。
まぁ、remainが60くらいになったら、何らかのアクションを起こすようなコードにすれば特に問題ないので良しとしよう。
参考にした記事
- ブラウザのスクロール量を取得するには?
- ブラウザの表示領域のサイズを取得する方法
- ブラウザのスクロールバーで隠れている領域を含むサイズを取得する方法
JJUGクロスコミュニティカンファレンス2008Springに参加した
各セッションの内容をメモしておく。
参加したセッション
Click Framework
※発表資料 http://amateras.sourceforge.jp/resources/ClickFramework.pdf
- コンポーネント指向
- イベント駆動
- シンプルでコンパクトなフレームワーク
- ゆえに開発者にとって理解しやすく、拡張しやすい
- 薄いフレームワークなので高性能(Strutsと同等)
- 理想と現実の妥協点
- Click+S2DaoでのアジャイルWeb開発プロジェクト
- 期間は3ヶ月
- 外部設計からテストまで
- 顧客の仕様が固まっておらず作りながら確定したいというありえない要求
- 60画面
- アプリ自体はわりと単純なもの
- HTMLモックは作らない。Clickでいきなり画面作成
- 自動レイアウト機能はあまり使えなかった。まずは自動レイアウト機能で作っておいて、顧客の要望に対応できなければHTMLテンプレートを作成
- Clickのビミョーなところ
- ビューがコントローラを侵食している。Pageクラスがビューを構築するためのコードで埋め尽くされる
- HTMLモックをつくるようなケースでは向いていない
- 既存のコンポーネントが微妙に拡張しづらい。(特にJavaScript)
- 割と保守的(Java1.4ベースで動作するように設計されている)
- ググラビリティが低い(Clickで検索してもまず引っかからない)
Grails
Wicket
※発表資料 http://homepage.mac.com/benbrand/files/jjug-spring2008-wicket.pdf
- Webページを生成するためのフレームワーク(Strutsと同じポジション)
- JavaとHTMLだけでアプリを作成する
- Webデザイナとプログラマとの協同
- デザイナがツールを使って作成したHTMLにWicket用のおまじないを挿入
- しかしHTMLは壊さないため、同じHTMLファイルをデザイナがツールを使って再編集できる
- 今後Webアプリ開発はステートフルなフレームワークが活用される傾向(JBoss Seamもステートフル)
- ステートフルなオブジェクト指向を実現
- Sessionはバンバン使う。
- Session管理=メモリ管理
- Javaであることを大切にする
- オブジェクト指向をフル活用
- 匿名クラスをよく使う。Swingのような感じ。
- 実績は意外と多い
- Wicket in Actionが出る。
パネルセッション(Webアプリケーションフレームワークについて)
- Struts vs Struts以外
- ほとんどのJava開発者はStrutsでの開発を経験
- なんだかんだで結局はStrutsになることが多い
- Strutsが登場したころのWebアプリの世界は、Strutsで十分だった
- Webの進化と共にWebアプリやWebアプリ開発に求められる要素も多くなった
- もはやStrutsで開発するには時代が遅れすぎているのではないか
- 様々なWebアプリケーションフレームワークの登場、乱立
- でもStrutsはStrutsで悪くはない。Webアプリ開発に対する貢献度は非常に大きい
- Webアプリ開発の2つのアプローチ
- Struts以外を利用する場合には、経営層にとって明らかなメリットが必要
- 納期、コスト、品質などの面でのメリットが必要
- エンジニアが幸せになる、ではダメ
- 第2のStrutsとなるWebアプリケーションフレームワークを作るためには開発者数の確保が必須
教科書に載っていないアジャイルプロセス開発
世界のナベアツ by JavaScript
これにインスパイヤされて反射的に実装。
http://q.hatena.ne.jp/1207585413
var NabeAtsu = function() { for(var i = 1; i <= 40; i++) { var msg = ""; if (i % 3 == 0 || (i + "").indexOf("3") >= 0) { msg += "アホ"; } if (i % 5 == 0) { msg += (msg == "" ? "" : "な") + "犬になる"; } else { msg += (msg == "" ? "普通" : "になる"); } alert(i + ":" + msg); } }; NabeAtsu()
あんまりスマートではないかなぁ。。
クロスコミュニティカンファレンス2008に反射的に申し込んだ
社内のお勉強プロジェクトで使っているオープンソースJavaフレームワーク「Click Framework」。
Click Frameworkのコミッタでもある、たけぞうさんこと竹添直樹さんによるClickのセッションが行われるらしいので反射的に申し込みました。
お勉強プロジェクトで使ってみて分かったのですが、Click Frameworkは拡張が本当にしやすく、実開発でも十分に使えると考えています。
あまり日本では(世界でも?)実績がなさそうなClick Frameworkですが、Clickを使ったアジャイル開発の実例について話を聞ける貴重な機会なので参加することにしました。
セッションの内容を社内にフィードバックして、実開発で使えたら楽しそうです。
OmniFind Yahoo! Editionインストールメモ(Windows)
部内の成果物はファイルサーバにフォルダ分けされて管理されているが欲しい材料をすぐに見つけるのは難しい。
そんな状況で、成果物を全文検索できるようにしてほしいと頼まれていろいろ調べているうちに見つけた。OmniFind Yahoo! Edition。
こいつはなかなか素晴らしい!
OmniFind Yahoo! Editionって?
企業向け全文検索ソリューション。企業向けのGoogleデスクトップみたいなもの。
インストール手順(Windows)
- http://omnifind.ibm.yahoo.net/register/form.php でメアドを入力してダウンロード
- ダウンロードしたexeファイルをクリックし、インストーラに従いインストール
- インストールフォルダの指定
- 管理者のアカウントを作成
以上、終了。めちゃ簡単。
OmniFind Yahoo! Editionを起動
- デスクトップにアイコンを作った場合は、アイコンクリック。
- 作ってない場合は、スタートメニューから。
- アプリケーションサーバ(Jetty)上で起動し、ブラウザにログイン画面が表示される。
- 作成した管理者アカウントでログイン。管理者画面が立ち上がる
検索対象ファイルのインデックスを作成
ファイルサーバ上にあるファイルを検索対象にするには、ファイルサーバ上のルートフォルダにネットワークドライブを割り当てる必要がある。
今回はYドライブに割り当てた。
- 管理画面の「ファイル」>「ディレクトリーに追加、除去、または編集」を選択
- 「ディレクトリーの追加」ボタンを押下し、「Y:\」を指定
- 「除外するディレクトリー・パターン」で「*.zip」と指定(zipファイルは検索対象外に)
- 「保存」ボタン押下で、インデックスの作成開始
- しばらくすると完了
zipファイルを対象外に指定しなかった場合、インデックス作成中にアプリが停止してしまった。
1Gメモリを積んでいるPCだったが、どうやらインデックス作成中にメモリリークを起こした模様。(本家サイトをみると、推奨2Gって書いてある。)
いろいろ模索して、zipファイルのインデックス作成でこけていることが分かった。(zipファイルをメモリに展開してフニャフニャするうちにリソースがなくなったのか?)
とにかく、zipファイルを検索対象からはずすことで、問題なくインデックス作成することができた。
zipファイルの中まではいいよね〜、いいことにしよう。
さぁ、検索だ
検索ページを開くと、Googleのようなシンプルなページが表示される。あとは、キーワードを入力して、検索ボタンをクリックするだけ。レスポンスも良好。素晴らしい。