デザインパターン入門 マルチスレッド編まとめ

がーっと読んだ。実際に使うときの思い出しトリガーになるようにメモしておく。

Java言語で学ぶデザインパターン入門 マルチスレッド編

マルチスレッドプログラムの評価基準

  • 安全性 オブジェクトを壊さないこと
    • スレッドセーフなクラス
  • 生存性 必要な処理が行われること
    • 安全性を重視しただけでは生存性を下げてしまう場合がある。例えばデッドロック
  • 再利用性 クラスを再利用できること
    • スレッドの排他制御の仕組みや方針をうまくクラスの中に隠蔽すれば、再利用性の高いプログラムになる。
  • パフォーマンス 処理を高速・大量に行えること

安全性と生存性を守るのは必須。その上で、いかにして再利用性とパフォーマンスを上げるかが重要。

Single Thread Execution 「この橋を渡れるのは、たった一人」

Immutable 「壊したくとも、壊せない」

  • インスタンス生成後、状態が変化しないのであればImmutableパターンにすることを検討する
  • Immutableなオブジェクトにすると排他制御に必要がなくなることが大きなメリット
  • Immutableなクラスの設計には十分に注意を払うこと。特にプリミティブでないオブジェクトをメンバに持つ場合には。

Guarded Suspension 「用意できるまで、待っててね」

  • これも頻出パターン
  • インスタンスが適切な状態になるまで、ガード条件を使ってスレッドを待たせる。
  • ガード条件が変化したことをスレッドの通知(notifyAll)
  • ガード条件が満たされないなら待たずに帰る場合は、Balkingパターンを使う。

Balking 「必要なかったら、やめちゃおう」

  • Guarded Suspensionパターンで、ガード条件が満たされない場合に待たずに帰る

Producer-Consumer 「わたしが作り、あなたが使う」

  • あるスレッド(Producer)から別スレッド(Consumer)にデータを安全に渡したい。
  • ProducerとConsumerの処理スピードが違うとスループットが落ちる。
  • 中継地点にChannelを置く。Channelに複数個のデータを保持させ、処理スピードの違いを吸収する(スループット向上)

Read-Write Lock 「みんなで読んでもいいけれど、読んでる間は書いちゃダメ」

  • 複数のスレッドがインスタンスを共有、参照するだけのスレッド(Reader)と更新するスレッド(Writer)が存在
  • スレッドの排他制御をしないと安全性を確保できない。Single Thread Executionを使うとスループットが落ちる
  • まず、「Readerを制御するロック」と「Writerを制御するロック」を分ける
  • この2種類のロックを提供するReadWriteLockを導入する。
  • ReaderとWriter、Writer同士の排他制御は行い、Reader同士の排他制御は行わない(スループット向上)

Thread-Per-Message 「この仕事やっといてね」

  • スレッド(Client)がインスタンス(Host)のメソッドを呼び出している場合、メソッド処理が終了するまでHostから制御が戻ってこない。(応答性ダウン)
  • Hostが処理用のスレッドを新たに起動し、処理を任せる。Clientにはすぐに応答する。(メソッドの起動とメソッドの実行の分離)
  • 処理結果を戻したい場合は、Futureパターンを使う。
  • スレッドを使いまわしたい場合は、Worker Threadパターンを使う。

Worker Thread 「仕事が来るまで待ち、仕事が来たら働く」

  • Thread-Per-Messageパターンで、処理するスレッドをあらかじめ起動しておき、使いまわす。
  • リクエストを表現するインスタンスをWorkerスレッドに渡すときには、Producer-Consumerパターンを使う。

Future 「引換券をお先にどうぞ」

  • Thread-Per-MessageパターンやWorker Threadパターンで処理結果を得たい場合に使う。
  • Clientはリクエスト発行後、すぐにFutureインスタンスを受け取る
  • 処理終了後、Futureインスタンスに処理結果をセットする
  • Clientは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の代入をアトミックに行う。


Java言語で学ぶデザインパターン入門 マルチスレッド編

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で動作確認。このコードではOperaSafariではもしかしたら動かないかも。(下の参考記事を参照)
スクロールバーを一番下まで下げた場合、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

JRuby on Rails

※発表資料 http://www.eisbahn.jp/yoichiro/2008/05/jruby_on_rails.html

  • JVM上で動作するRails
  • Railsでは運用面での安定稼動がわりと難しいが(負荷分散とか)
  • JRuby on RailsではJavaEE上で動作するのでJavaEEの技術をそのまま流用可能。
  • でもほとんど実績がないため、本当に運用面でメリットがあるかどうかは不明
  • JRuby on Railsならではのメリット
  • JRuby on Railsのデメリット
    • 起動が遅い

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管理=メモリ管理
    • Sessionは悪ではない。むしろ便利
    • Sessionを開放し忘れることが悪
    • Wicketのページコンポーネントは必要がなくなれば自動開放される
  • Javaであることを大切にする
  • 実績は意外と多い
  • Wicket in Actionが出る。

パネルセッション(Webアプリケーションフレームワークについて)

教科書に載っていないアジャイルプロセス開発

  • 特に目新しい内容がなくてちょっと残念
  • KPT分析するときは、開発の流れを可視化したタイムラインがあるといろんな意見が出やすい
  • 計画ゲームをするときにはトリアージを常に意識する必要がる。
  • お客様へは「アジャイル」というキーワードを使わずにアジャイルできるように説明することも必要なことがある。
  • 伝えたいメッセージ 「今の開発方法を完璧と思わないこと」

ポストJavaは何か?JVMで動く関数型言語Scalaの可能性

  • どうやらかなりマニアックなセッションらしい
  • でも、会場は立ち見する人がいるほど盛況(あとのひがやすを氏のセッションに参加する人が多い?)
  • 時間都合により、途中退席

世界のナベアツ 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デスクトップみたいなもの。

  • 0円
  • MS Officeを含む200種類以上のファイルフォーマットに対応
  • 3クリックインストール。めちゃ簡単
  • 日本語対応されている
  • アプリケーションを操作するREST APIが用意されている

インストール手順(Windows

  1. http://omnifind.ibm.yahoo.net/register/form.php でメアドを入力してダウンロード
  2. ダウンロードしたexeファイルをクリックし、インストーラに従いインストール
    1. インストールフォルダの指定
    2. 管理者のアカウントを作成

以上、終了。めちゃ簡単。

OmniFind Yahoo! Editionを起動

  1. デスクトップにアイコンを作った場合は、アイコンクリック。
    1. 作ってない場合は、スタートメニューから。
  2. アプリケーションサーバ(Jetty)上で起動し、ブラウザにログイン画面が表示される。
  3. 作成した管理者アカウントでログイン。管理者画面が立ち上がる

検索対象ファイルのインデックスを作成

ファイルサーバ上にあるファイルを検索対象にするには、ファイルサーバ上のルートフォルダにネットワークドライブを割り当てる必要がある。
今回はYドライブに割り当てた。

  1. 管理画面の「ファイル」>「ディレクトリーに追加、除去、または編集」を選択
  2. ディレクトリーの追加」ボタンを押下し、「Y:\」を指定
  3. 「除外するディレクトリー・パターン」で「*.zip」と指定(zipファイルは検索対象外に)
  4. 「保存」ボタン押下で、インデックスの作成開始
  5. しばらくすると完了

zipファイルを対象外に指定しなかった場合、インデックス作成中にアプリが停止してしまった。
1Gメモリを積んでいるPCだったが、どうやらインデックス作成中にメモリリークを起こした模様。(本家サイトをみると、推奨2Gって書いてある。)
いろいろ模索して、zipファイルのインデックス作成でこけていることが分かった。(zipファイルをメモリに展開してフニャフニャするうちにリソースがなくなったのか?)

とにかく、zipファイルを検索対象からはずすことで、問題なくインデックス作成することができた。
zipファイルの中まではいいよね〜、いいことにしよう。

さぁ、検索だ

検索ページを開くと、Googleのようなシンプルなページが表示される。あとは、キーワードを入力して、検索ボタンをクリックするだけ。レスポンスも良好。素晴らしい。

話は変わって

OmniFind Yahoo! EditionはJava全文検索エンジンLuceneを使って作られている。OmniFindを見つけていなかったらLucene使って自作しようとも考えていたが、自作してもOmniFindほど完成度の高いものは作れなかっただろう。

また、管理画面はJavaScriptフレームワークDojoを使って作られている。使い勝手がとてもいい。見た目もかわいい感じ。UIの作り方としても勉強になった。