在OC中有dispatch_once来实现,在Swift中我们需要自己来根据其原理来实现,类似于增加一个哨兵来标识是否执行过了
原子操作
对于一个资源,在写入或读取时,只允许在一个时刻一个角色进行操作,则为原子操作。Swift中 let 声明的资源,永远是原子性的。在我们购买火车票时需要保证票数不会在多个线程中同时进行修改,这时就可以使用这种方式来实现。
- OC实现方式
// 加锁
@synchronized(<#token#>) {
<#statements#>
}
- Swift实现方式
objc_sync_enter(lock)
// TODO:
objc_sync_exit(lock)
购买火车票
// 在Playeground实现
import UIKit
var ticket = 10000
func buyTicket(userName: String) {
DispatchQueue.global().async {
// objc_sync_enter(ticket)
let count = ticket - 1
ticket = count
// objc_sync_exit(ticket)
print("\(userName)买了一张票,剩余票数\(ticket)")
}
}
for i in 1 ... 200 {
buyTicket(userName: "hc\(i)")
}
结果如下:
hc6买了一张票,剩余票数9999
hc3买了一张票,剩余票数9998
hc1买了一张票,剩余票数9999
hc4买了一张票,剩余票数9998
hc2买了一张票,剩余票数9999
hc7买了一张票,剩余票数9998
hc5买了一张票,剩余票数9998
hc8买了一张票,剩余票数9997
hc9买了一张票,剩余票数9997
hc10买了一张票,剩余票数9997
hc11买了一张票,剩余票数9996
hc12买了一张票,剩余票数9996
hc14买了一张票,剩余票数9995
hc13买了一张票,剩余票数9995
hc15买了一张票,剩余票数9994
hc16买了一张票,剩余票数9994
hc17买了一张票,剩余票数9994
hc19买了一张票,剩余票数9994
hc18买了一张票,剩余票数9994
hc20买了一张票,剩余票数9993
hc22买了一张票,剩余票数9993
hc21买了一张票,剩余票数9993
hc23买了一张票,剩余票数9993
hc24买了一张票,剩余票数9992
hc25买了一张票,剩余票数9992
hc26买了一张票,剩余票数9991
hc27买了一张票,剩余票数9991
hc28买了一张票,剩余票数9991
hc29买了一张票,剩余票数9991
···
将加锁部分objc_sync_enter(ticket)
,objc_sync_exit(ticket)
打开后结果如下:
hc1买了一张票,剩余票数9999
hc9买了一张票,剩余票数9998
hc12买了一张票,剩余票数9997
hc17买了一张票,剩余票数9996
hc20买了一张票,剩余票数9995
hc21买了一张票,剩余票数9994
hc22买了一张票,剩余票数9993
hc23买了一张票,剩余票数9992
hc24买了一张票,剩余票数9991
hc25买了一张票,剩余票数9990
hc26买了一张票,剩余票数9989
hc27买了一张票,剩余票数9988
hc28买了一张票,剩余票数9987
hc33买了一张票,剩余票数9986
hc38买了一张票,剩余票数9985
hc42买了一张票,剩余票数9984
hc47买了一张票,剩余票数9983
hc51买了一张票,剩余票数9982
hc55买了一张票,剩余票数9981
···
dispatch_once在Swift中的实现
extension DispatchQueue {
fileprivate static var _onceToken = [String]()
static func once(token: String, block: () -> Void) {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if _onceToken.contains(token) {
return
}
_onceToken.append(token)
block()
}
}
网友评论