前言
線程同步機制是多線程下解決線程對共享資源競爭的主要方式,華為倉頡語言提供了三種常見的同步機制用來保證線程同步安全,分別是原子操作,互斥鎖和條件變量。本篇文章詳細介紹主要倉頡語言解決同步機制的方法,建議點贊收藏!
同步機制
原子操作
和 java 一樣,倉頡也支持使用原子操作(Atomic)用來確保多線程下的數據訪問安全。主要是提供整數類型,布爾類型和引用類型三種方式。
以整數類型為例,原子變量 Atomic 包括 8 位(AtomicInt8) 至 64 位(AtomicInt64)的整數類型,同時支持基本數據的讀寫。
- 不使用原子操作,在多線程情況下對數據進行累加。
var sum: Int64 = 0for (pattern in 1..100) {spawn {sum += 1 }}sleep(Duration.second*2)AppLog.info("Main===${sum}") //輸出 Main===96
- 使用原子變量 AtomicInt64 對數據進行累加。
var sum = AtomicInt64(0)for (pattern in 1..100) {spawn {sum.fetchAdd(1)}}sleep(Duration.second*2)AppLog.info("Main===${sum.load()}")//輸出 Main===99
原子操作 Atomic 使用compareAndSwap 用于數據的交換,使用的和 Java 中一樣的 CAS 同步機制用于確保在多線程的情況下能夠交換成功。
可重入互斥鎖
倉頡語言中同樣支持使用可重入互斥鎖(ReentrantMutex)來解決多線程的同步問題。當一個線程獲取到共享變量的鎖時,在該線程釋放鎖之前,其他線程都無法訪問該共享變量,直到該線程持有的同步鎖釋放。
ReentrantMutex 可重入互斥鎖主要提供了三個方法 ,分別是 lock(),unlock(),tryLock()。lock()和 unlock()總是成對出現的,及對共享變量加完鎖后,等使用結束必須及時釋放鎖。
lock()和unlock()
還是以在多線程下對數據進行累加操作。
var sum = AtomicInt64(0)let mutex = ReentrantMutex()for (pattern in 1..100) {spawn {mutex.lock()sum +=1mutex.unlock()}}sleep(Duration.second*2)AppLog.info("Main===${sum}")//輸出 Main===99
ReentrantMutex 作為可重入互斥鎖,當已經獲取互斥鎖的線程再次獲取該互斥鎖時,可以直接獲取。但是該線程獲取幾次互斥鎖就需要釋放幾次鎖。
tryLock()
tryLock 表示線程嘗試去獲取鎖,但是并一定能夠獲取到。可以通過 tryLock()返回到布爾值判斷該線程釋放獲取到鎖,然后調用 unLock 釋放鎖。
Monitor
Monitor 是一個內置鎖,繼承于ReentrantMutex 可重入互斥鎖。Monitor 不僅可以使用 lock(),unlock(),tryLock() 還提供了 wait(),notify(),notifyAll()三個方法用于解決線程間的數據安全問題,這一點和 java 不同,java 中的 Object 提供了 wait(),notify(),notifyAll()三個方法。而 在倉頡中是單獨封裝的類。
下面舉例說明:
let fun = spawn {monitor.lock()while (flag) {AppLog.info("Main=== thread 1 開始執行")monitor.wait()AppLog.info("Main=== thread 1 執行結束")}monitor.unlock()}sleep(Duration.second)monitor.lock()AppLog.info("Main=== 主線程開始執行")flag = false AppLog.info("Main===主線程執行結束") monitor.notifyAll() monitor.unlock() fun.get() //輸出
// Main=== thread 1 開始執行
// Main=== 主線程開始執行
// Main===主線程執行結束
// Main=== thread 1 執行結束
需要注意的是 monitor 的 wait 和 notify/notifyAll 方法使用之前必須要先獲取到鎖,即 lock()。
總結
倉頡中的多線程并發安全同步機制十分重要,對于會 Java 的小伙伴來說簡單容易上手,但是也有一些需要注意的點,比如 notify 調用前必須要獲取到線程鎖,用完必須釋放否則會導致其他線程無法獲取到鎖,本篇文章就先講這些,已經學會了的小伙伴,趕快動手試試吧!。