常用API:
let semaphore = DispatchSemaphore.init(value: 1)
//初始化信号量 value根据自己的需求来设
semaphore.wait()
// 如果信号量的值>0,就减1,然后往下执行后面的代码
// 如果信号量的值<=0,当前线程就会进入休眠等待,直到信号量的值>0
semaphore.signal()
// 让信号量的值增加1,信号量值不等于零时,前面的等待的代码会执行
信号量semaphore常用场景
1.设置最大并发数
/**
* 最大并发
*/
func concurrent(){
let semaphore = DispatchSemaphore.init(value: 2)//最大并发数量
for i in 0...5 {
DispatchQueue.global().async {
semaphore.wait()
print("run task\(i) ---\(Thread.current)")
sleep(1)//耗时操作
print("comlete task\(i)")
semaphore.signal()
}
}
print("mainThread")
}
输出:
mainThread
run task0 ---<NSThread: 0x2808cfe40>{number = 4, name = (null)}
run task1 ---<NSThread: 0x2808ed780>{number = 5, name = (null)}
comlete task1
comlete task0
run task3 ---<NSThread: 0x2808cee80>{number = 3, name = (null)}
run task2 ---<NSThread: 0x2808e9580>{number = 6, name = (null)}
comlete task3
comlete task2
run task4 ---<NSThread: 0x2808e13c0>{number = 7, name = (null)}
run task5 ---<NSThread: 0x2808e9740>{number = 8, name = (null)}
comlete task4
comlete task5
并发执行2个任务,保证同一时间执行的线程数不超过2
2.保持线程同步,将异步执行任务转换为同步执行任务
/**
* semaphore 线程同步
*/
func semaphoreSync(){
print("mainThread---\(Thread.current)")
print("begin")
let semaphore = DispatchSemaphore.init(value: 0)
var number = 0
DispatchQueue.global().async {
sleep(2)//耗时操作
print("1---\(Thread.current)")
number = 100
semaphore.signal()
}
semaphore.wait()//等待异步任务执行完成才可以继续执行
print("end,number = \(number)")
}
输出:
mainThread---<NSThread: 0x280ac1f00>{number = 1, name = main}
begin
1---<NSThread: 0x280aaa340>{number = 6, name = (null)}
end,number = 100
3.保证线程安全,为线程加锁
场景:总共有 50 张火车票,有两个售卖火车票的窗口。两个窗口同时售卖火车票,卖完为止。
/**
* 非线程安全:不使用 semaphore
* 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
*/
func initTicketStatusNotSave(){
print("mainThread---\(Thread.current)")
let queue1 = DispatchQueue.init(label: "queue1")//窗口1
let queue2 = DispatchQueue.init(label: "queue2")//窗口2
queue1.async {
self.saleTickeNotSafe()//开始卖票
}
queue2.async {
self.saleTickeNotSafe()//开始卖票
}
}
/**
* 售卖火车票(非线程安全)
*/
func saleTickeNotSafe(){
while true {
if self.num > 0{
self.num = self.num - 1
print("剩余票数:\(self.num), 窗口:\(Thread.current)")
Thread.sleep(forTimeInterval: 0.2)
}else{
print("所有火车票已卖完")
break
}
}
}
输出:
mainThread---<NSThread: 0x28155d200>{number = 1, name = main}
剩余票数:49, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:48, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:45, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
剩余票数:44, 窗口:<NSThread: 0x281503380>{number = 5, name = (null)}
剩余票数:42, 窗口:<NSThread: 0x281503b40>{number = 6, name = (null)}
.....
剩余票数:0, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
所有火车票已卖完
可以看到在不考虑线程安全的情况下数据是错乱的。
线程安全(使用 semaphore 加锁)
/**
* 使用 semaphore
* 初始化火车票数量、卖票窗口、并开始卖票
*/
func initTicketStatusSave(){
print("mainThread---\(Thread.current)")
let queue1 = DispatchQueue.init(label: "queue1")//窗口1
let queue2 = DispatchQueue.init(label: "queue2")//窗口2
self.semaphore = DispatchSemaphore.init(value: 1)//初始化信号量值为1
queue1.async {
self.saleTickeSafe()//开始卖票
}
queue2.async {
self.saleTickeSafe()//开始卖票
}
}
/**
* 售卖火车票
*/
func saleTickeSafe(){
while true {
self.semaphore.wait()//检测信号量:大于0减1继续执行,少于等于0则等待
if self.num > 0{
self.num = self.num - 1
print("剩余票数:\(self.num), 窗口:\(Thread.current)")
Thread.sleep(forTimeInterval: 0.2)
}else{
print("所有火车票已卖完")
self.semaphore.signal()//信号量加1
break
}
self.semaphore.signal()//信号量加1
}
}
输出:
mainThread---<NSThread: 0x28062af40>{number = 1, name = main}
剩余票数:49, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:48, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:47, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:46, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:45, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
剩余票数:44, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
剩余票数:43, 窗口:<NSThread: 0x280666440>{number = 4, name = (null)}
.....
剩余票数:0, 窗口:<NSThread: 0x28064aac0>{number = 5, name = (null)}
所有火车票已卖完
相关简书:
iOS GCD学习总结(一)
iOS GCD学习总结(二)
iOS 线程同步方案学习总结
信号量semaphore学习总结
iOS dispatch_barrier_sync实现多读单写
NSOperation和NSOperationQueue学习总结