はじめに
N予備校で「Scala基礎」「Scala応用」「並行処理プログラミング」を受講しています。今回からしばらくは並行処理についてになります。
並行性
マルチプロセスやマルチスレッドで実現している CPU のリソース数に限らず、複数の数のタスクを実行する性質のこと
object ThreadTest extends App {
println(Thread.currentThread().getName)
val thread = new Thread(() => {
Thread.sleep(1000)
println(Thread.currentThread().getName)
})
thread.start()
println("main thread finished.")
}
currentThread
は現在の処理が実行しているスレッドのインスタンスを取得する。
synchronizedブロック
object ThreadRisk extends App {
private var counter = 0
def next(): Int = synchronized {
counter = counter + 1
counter
}
for (i <- 1 to 10) {
new Thread(() => {
for (j <- 1 to 100000) {
println(next())
}
}).start()
}
}
一つしかこの処理を通らないようにする、アトミックに行われることを保証する。
一連の処理を原子のようにこれ以上分解できない単一の単位処理として行うことを、アトミックな処理という。
スレッドセーフ
複数のスレッドで操作した場合に正しく動かない実装の状態のことを「スレッドセーフではない」という。
・可変の状態を複数のスレッドが共有しないようにする
・可変の状態を不変にする
・可変の状態へのアクセスを常に同期化する
このいずれかを対処し、マルチスレッドへの対応がされたオブジェクトやクラスなどがスレッドセーフ
という。
object CheckThenAct extends App {
for (i <- 1 to 100) {
new Thread(() => {
println(SingletonProvider.get)
}).start()
}
}
object SingletonProvider {
private[this] var singleton: BigObject = null
def get: BigObject = this.synchronized {
if (singleton == null) {
singleton = new BigObject()
}
singleton
}
}
class BigObject() {
Thread.sleep(1000)
}
this synchronized
this
というインスタンスでロックを取得する。
ロックとは、その処理が指定したインスタンスで1 つしか実行されないように カギをかけること
まとめ
ロックした処理の中で重い処理を実行した場合、全体のパフォーマンスにも関わってくるので、synchronized
を使う時は注意が必要、とのこと。