はじめに
N予備校でScalaの「並行処理プログラミング」を受講しています。
メモリの可視性
複数のスレッドで共有している状態の変数への変更は、変更したスレッドからは見えるが、もう一方のスレッドからはその変更が見えない。
「可視性がない」状態。
yield
他の実行可能なスレッドがある場合は実行する、ない場合は待つ。
object MemoryVisibility extends App {
var number = 0
var ready = false
new Thread(() => {
while (!ready) {
Thread.`yield`()
}
println(number)
}).start()
number = 2525
ready = true
}
同期が取れていないので、実行環境によって結果はまちまち。
ready
やnumber
の変更が別スレッドから感知できないため。
volatile アノテーション
@volatile
がついた変数は、Javaのコンパイラとランタイムにおいて、
複数のスレッドから共有される変数と認識される。
@volatile var number = 0
@volatile var ready = false
アトミックな処理を求める同期化が必要な場合には使えないので、
その場合はsynchronized
ブロックを使うこと。
逸出
逸出とは、本来の公開すべきではないフィールドのオブジェクトや変数が公開されてしまうこと。
var
や可変オブジェクトを利用しないのが一つの手段。
変数の宣言はprivate[this] val
などで行う。
スレッド拘束
データが必ず 1 つのスレッドからしかアクセスされないようにする
特定のスタックからインスタンスの参照が漏れることの無いようにする方法
並列コレクション
java.util.concurrent
の利用。
synchronized
ブロックなどの処理をAPIとして提供する並行コレクション。
ConcurrentHashMap
ハッシュマップをスレッドセーフにした部品。
並行処理で更新などをしても パフォーマンスが出る。
CopyOnWriteArrayList
ArrayList
はスレッドセーフでないために、並行処理を行う場合に利用する。
Seq
やSet
を使う場合がほとんど。
BlockingQueue
分散処理システムを実装できる並行処理部品。
メインスレッドが仕事をキューに入れて、ワーカースレッドが仕事のキューを消化していく。
シンクロナイザ
スレッドの制御フローを扱える部品のこと
- ラッチ
最終ステートに到着するまでせき止めておくゲートの働きをする部品 - FutureTask
計算結果が取得可能な Runnable 途中でキャンセルする機能も - セマフォ
Semaphore 何かのリソースにアクセスさせる際、その数を制限したい時に用いる並行処理部品 - バリア
他のスレッドが全員揃ったらスタートできるといういう並行部品
まとめ
並行処理はコード見ただけでは結果がすぐにわからない。
それぞれ違いは実際使ってみて理解していくしかないかなと思います。