タグ: Java

Jakarta Commons CLI

  • Jakarta Commons CLI
    • コマンドライン引数をパースしてというCLI(Command Line Interface)
    • Options: 受け取れるオプション
    • addOptionで受け取れる引数を追加していく
    • parser.parse(options, args)とするとパースした結果を得られる

phax/ph-cssを使う

phax/ph-css の使い方

b080e264-d67f-11e4-845e-c1f3fdff6678

便利

Immutable パターン

結城先生のデザパタ本マルチスレッド編 第2章のまとめ

問題

複数のスレッドがインスタンスを共有しているが、インスタンスの状態は変化しない。
このときに、何も考えず Single Threaded Execution パターンを使うとスループットが落ちてしまいます。

解決方法

インスタンスが状態変化しないのであれば Single Threaded Execution パターンを使う必要はありません。
その場合は意図しない状態変化を防ぐためにフィールドが変化しないようにする Immutable パターンを用います。
不変性を保つのは大変なので、気をつけて実装する必要があります。またドキュメントにクラスが不変であることを明示する方が良いでしょう。

関連するパターン

  • 状態を変更するスレッドが参照するスレッドの数よりも少ないときは、Read-Write Lock パターンが使えます

コード例はあまりにもつまらないので割愛

適用可能性

  • インスタンスの生成後、状態が変化しない時
  • インスタンスが共有され、頻繁にアクセスされるとき

余談

mutable なクラスと immutable なクラス

Java 標準ライブラリには mutable なクラスと immutable なクラスが対になっているものがある。

  • java.lang.String
  • java.lang.StringBuffer

不変性を守るために

  • フィールドの保持している mutable なインスタンスをそのまま返すようなことをすると不変性が破られる可能性がある
  • コンストラクタに引数として渡したインスタンスをそのままフィールドに代入した場合、不変性が破られる可能性がある

Single Threaded Executionパターン

結城先生のデザパタ本マルチスレッド編 第1章のまとめ

問題

複数のスレッドがインスタンスを共有している状態で、
それぞれのスレッドがインスタンスの状態を勝手に変更すると、インスタンスの安全性が失われます。

解決方法

そこで、そのままではインスタンスが不定な状態に陥ってしまう範囲を定めます。
これをクリティカルセクションと呼びます。
このクリティカルセクションを synchronized を用いて1つのスレッドだけが実行できるようにガードします。
このようなパターンを Single Threaded Execution パターンと呼びます。

関連するパターン

  • インスタンスの状態が変化しないときには Immutable パターンを使うことにより、スループットを向上させることができる
  • インスタンスの状態を参照するスレッドと変更するスレッドが分かれている場合は Read-Write Lock パターンを使うことにより、スループットを向上させることができる

以下のようなカウンターがあったとします

これを次のように複数のスレッドから呼び出すとおかしなことが起こります

実行すると同じ値がログ出力されたり、
300回 increment が呼び出されているはずなのに、最後のログ出力が 300 になっていなかったりするはずです。
increment はインスタンス内部の状態を変化させるメソッドであり、複数のスレッドから呼び出すと予期せぬ挙動をとります。
この部分をクリティカルセクションとして保護してあげれば良いでしょう。単に synchronized をつければよいだけです。

パフォーマンスのために、一般にクリティカルセクションは小さく保つほうが良いでしょう。

適用可能性

  • 複数のスレッドからクラスへのアクセスが行われるとき
    • シングルスレッドで実行するプログラムにはこのような対応は必要ない。
  • クラスが状態変化する可能性を持っているとき
  • 安全性を保つ必要があるとき

余談

long と double はアトミックに扱われない

Javaのprimitive型の参照や代入は基本的にアトミックです。
しかし、longdouble に関してはアトミックではありません。

例えば、同じ long フィールドに対して、異なる2つのスレッドから同時に 5678, 1234 という形で代入をおこなったとします。
するとこのフィールドがどのような値をとるか保証されません。この場合は synchronized を使うか volatile キーワードを使うという手があります。

まとめると

  • 基本型・参照型の参照・代入はアトミック
  • long, double に関しては例外
  • long, double をスレッド間で共有する場合は synchronizedvolatile を使う

計数セマフォ

synchronized を使うと、ある領域を1つのスレッドのみが実行できるように制限できますが、
n個のスレッドのみが実行できるようにしたいなどという場合には計数セマフォというものが用意されている。

使い方は簡単で次のような感じ

Java言語で学ぶデザインパターン 〜マルチスレッド編〜 読書メモ (1)

結城先生のデザパタ本マルチスレッド編がサクッと読めそうだったので読み進めているので、自分用メモ。ほとんど知っている内容ではあったけど、体系的に知識が入っていなかったので、よい確認になる…。

Java 言語のスレッド

スレッドの起動方法

スレッドを起動する方法は2つある

  1. Thread クラスのサブクラスのインスタンスを使ってスレッドを起動する
  2. Runnable インターフェースの実装クラスのインスタンスを使ってスレッドを起動する

それぞれ run() メソッドを実装している。これらを直接呼び出した場合、呼び出したスレッドで処理が実行される。別のスレッドで実行させたい場合は、start() を呼び出す必要がある。以下のテストを実行すると、run() の呼び出しはメインスレッドから行なわれているのが観測できる。

スレッドの生成には ThreadFactory なるものを使うこともできる。これにより Threadnew せずに済む。

Thread の排他制御

  1. synchronized メソッドを使う
  2. synchronized ブロックを使う

あるスレッドから synchronized インスタンスメソッドが呼ばれている間は、
他のスレッドは同じインスタンスの synchronized メソッドを呼び出すことができない。
非 synchronized インスタンスメソッドについては問題なく呼び出すことができる。
ロックはインスタンスごとにされる点に注意。

次の synchronized メソッド と synchronized ブロックを使ったメソッドは等価になります。

また、次の synchronized クラスメソッドと synchronized ブロックを使ったクラスメソッドは等価になります。

スレッドの排他制御をする仕組みを モニタ と呼びます。
また、ロックをとっていることをモニタを所有する、あるいはロックをホールドすると呼ぶこともあります。

スレッドの協調

各インスタンスはウェイトセットという仮想的な概念を持っています。
あるインスタンスがあるスレッドに wait メソッドを呼び出されたとき、インスタンスのウェイトセットにそのスレッドが追加されます。
スレッドは notify, notifyAll, interrupt の呼び出しが発生するか wait のタイムアウトが発生するまで停止します。
synchronized 文やブロックの外側で オブジェクトの wait を呼び出すと IllegalMonitorStateException が発生がスローされます。

スレッドには処理をキャンセルする機能があったり、優先度を設定できたり、スレッドの終了待ちをできたりもする。

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

  • 安全性(safety): オブジェクトを壊さないこと
  • 生存性(liveness): 必要な処理が行われること
  • 再利用性(reusability): クラスを再利用できること
  • パフォーマンス(performance): 処理を高速・大量に行えること

うち安全性と生存性を守るのは必須