Java併發編程最常用和易用的技術莫過於synchronized關鍵字,而Scala的併發編程之旅也可以從synchronized開始。而synchronized的背後其實是monitor技術。
什麼是Monitor
Monitor是解決併發編程問題的一種常用技術,可以有效解決互斥和同步兩大常見問題,通常翻譯爲‘監視器’或‘管程’。個人認爲‘管程‘更能表達monitor的含義,指的是管理共享變量以及對共享變量的操作過程,讓他們支持併發。
Scala的synchronized
Synchronized是Java對monitor的實現,可以對代碼塊或方法使用,使得每次只能有一個線程訪問,實現了線程互斥。當一個線程獲取了鎖,其他線程將在隊列上等待,實現了線程同步。
Scala延用了這一關鍵字,但是語法有所不同。
//用於代碼塊
obj.synchronized {
...
}
//用於方法
def func(): Unit = this.synchronized {
...
}
跟Java一樣,這裏的this是可以省略的,因爲默認加鎖的對象就是this,但是不建議省略。
Scala實例
import java.util.concurrent.TimeUnit
object SynchronizedDemo {
private var inc: Int = 0
def addOne(): Unit = this.synchronized {
TimeUnit.SECONDS.sleep(1)
inc = 1
}
def main(args: Array[String]): Unit = {
for (i <- 1 to 10) {
new Thread {
override def run(): Unit = {
println(s"run thread with object method $i")
addOne()
}
}.start()
}
val instance = new SynchronizedDemo
for (i <- 1 to 10) {
new Thread {
override def run(): Unit = {
println(s"run thread with class method $i")
instance.addOne()
}
}.start()
}
while (true) {
println(s"object inc=$inc, class inc=${instance.inc}")
TimeUnit.SECONDS.sleep(1)
}
}
}
class SynchronizedDemo {
private var inc: Int = 0
def addOne(): Unit = this.synchronized {
TimeUnit.SECONDS.sleep(1)
inc = 1
}
}
程序輸出
run thread with class method 7
run thread with class method 4
run thread with object method 8
run thread with object method 7
run thread with class method 10
run thread with class method 8
run thread with class method 9
run thread with object method 5
run thread with object method 3
run thread with object method 2
run thread with object method 4
run thread with object method 10
run thread with object method 9
run thread with class method 5
run thread with class method 3
object inc=0, class inc=0
run thread with object method 1
run thread with class method 6
run thread with class method 1
run thread with class method 2
run thread with object method 6
object inc=1, class inc=1
object inc=2, class inc=2
object inc=3, class inc=2
object inc=4, class inc=4
object inc=5, class inc=5
object inc=6, class inc=6
object inc=7, class inc=7
object inc=8, class inc=8
object inc=9, class inc=9
object inc=10, class inc=10
解析
- 在object SynchronizedDemo和class SynchronizedDemo中均定義了一個inc變量和一個addOne方法,addOne方法的作用就是將inc加1。
- main方法中,分別創建10個線程調用addOne方法,對inc進行10次加1操作。
- 因爲inc變量不是線程安全的,所以對addOne方法加上synchronized關鍵字,使得修改操作是線程安全的。這樣才能保證inc會從1加到10。
- object和class中的this並不相同,object中的this指向的是名爲SynchronizedDemo的object對象,class中的則是該class實例化後的對象。(Scala中沒有靜態類和靜態方法,object SynchronizedDemo實際上是創建名爲SynchronizedDemo的單例對象)
如果把class中定義的addOne改成如下:
def addOne(): Unit = SynchronizedDemo.synchronized {
TimeUnit.SECONDS.sleep(1)
inc = 1
}
兩處定義的addOne方法就會互斥,輸出就會變成如下:
run thread with object method 2
run thread with object method 1
run thread with object method 3
run thread with object method 4
run thread with object method 5
run thread with object method 6
run thread with object method 7
run thread with object method 8
run thread with object method 9
run thread with object method 10
run thread with class method 1
run thread with class method 2
run thread with class method 3
run thread with class method 4
run thread with class method 5
run thread with class method 6
run thread with class method 7
run thread with class method 8
run thread with class method 9
run thread with class method 10
object inc=0, class inc=0
object inc=1, class inc=0
object inc=1, class inc=1
object inc=1, class inc=2
object inc=1, class inc=3
object inc=1, class inc=4
object inc=1, class inc=5
object inc=1, class inc=6
object inc=1, class inc=7
object inc=1, class inc=8
object inc=1, class inc=9
object inc=1, class inc=10
object inc=2, class inc=10
object inc=3, class inc=10
object inc=4, class inc=10
object inc=5, class inc=10
object inc=6, class inc=10
object inc=7, class inc=10
object inc=8, class inc=10
object inc=9, class inc=10
object inc=10, class inc=10
本文代碼
轉載請註明原文地址:https://liam-blog.ml/2019/07/14/Scala-Concurrency-in-Practice-1/