Scala併發編程實戰:Monitor與synchronized

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

本文代碼

Github倉庫

轉載請註明原文地址:https://liam-blog.ml/2019/07/14/Scala-Concurrency-in-Practice-1/

查看更多博主文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章