1. 程式人生 > 程式設計 >Scala併發程式設計實戰:Monitor與synchronized

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=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倉庫

轉載請註明原文地址:liam-blog.ml/2019/07/14/…檢視更多博主文章