前言
多線程是現在每個開發必定知道的。這哥們(多線程)是用來干啥的?舉個例子拿單線程來說,單線程就是你寫的代碼一步一步執行,完全按照順序執行,科技一步一步進步,現在CPU核心數越來越多,多線程也就成為了現在每個程序員必回的一個知識點。但是使用多線程優點就不多說了。要說都是優點沒缺點,這純瞎說,他的弊端就是資源搶占問題,開辟多條線程占用一定的資源(主線程一般1MB ,其他線程512kb,一般建議同時最多開三條線程比較合理)。關于資源搶占問題下面就舉個例子:在使用多線程的時候多個線程可能會訪問同一塊資源,這樣就很容易引發數據錯亂和數據安全等問題。解決資源爭用,最直接的想法是引入鎖,對并發讀寫的數據進行保護,保證每次只有一個線程訪問這一塊資源。
??鎖是最常用的同步工具:一塊公共資源在同一個時間只能允許被一個線程訪問,比如一個線程A進入加鎖資源之后,由于已經加鎖,另一個線程B就無法訪問,只有等待前一個線程A執行完后解鎖,B線程才能訪問加鎖資源。
為什么需要鎖?
?以常見的火車站賣票為例,假設有20張票,有兩個窗口同時售票:
- (void)ticketTest{
self.ticketsCount = 20;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 線程1
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self sellingTickets];//多線程售票
}
});
// 線程2
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self sellingTickets];//多線程售票
}
});
}
- (void)sellingTickets{
NSInteger oldMoney = self.ticketsCount;
sleep(0.2);
oldMoney -= 1;
self.ticketsCount = oldMoney;
NSLog(@"當前剩余票數-> %ld", oldMoney);
}
不加鎖
2019-02-21 17:10:40.861358+0800 多線程測試[8167:20874670] 當前剩余票數-> 19
2019-02-21 17:10:40.861358+0800 多線程測試[8167:20874671] 當前剩余票數-> 19
2019-02-21 17:10:40.861723+0800 多線程測試[8167:20874671] 當前剩余票數-> 18
2019-02-21 17:10:40.861723+0800 多線程測試[8167:20874670] 當前剩余票數-> 18
2019-02-21 17:10:40.861851+0800 多線程測試[8167:20874670] 當前剩余票數-> 17
2019-02-21 17:10:40.861961+0800 多線程測試[8167:20874670] 當前剩余票數-> 16
2019-02-21 17:10:40.861989+0800 多線程測試[8167:20874671] 當前剩余票數-> 16
2019-02-21 17:10:40.862066+0800 多線程測試[8167:20874670] 當前剩余票數-> 15
2019-02-21 17:10:40.862222+0800 多線程測試[8167:20874670] 當前剩余票數-> 14
2019-02-21 17:10:40.863234+0800 多線程測試[8167:20874671] 當前剩余票數-> 13
2019-02-21 17:10:40.863958+0800 多線程測試[8167:20874670] 當前剩余票數-> 12
2019-02-21 17:10:40.864225+0800 多線程測試[8167:20874671] 當前剩余票數-> 11
2019-02-21 17:10:40.864529+0800 多線程測試[8167:20874670] 當前剩余票數-> 10
2019-02-21 17:10:40.865159+0800 多線程測試[8167:20874671] 當前剩余票數-> 9
2019-02-21 17:10:40.865498+0800 多線程測試[8167:20874670] 當前剩余票數-> 8
2019-02-21 17:10:40.865777+0800 多線程測試[8167:20874671] 當前剩余票數-> 7
2019-02-21 17:10:40.866747+0800 多線程測試[8167:20874670] 當前剩余票數-> 6
2019-02-21 17:10:40.866970+0800 多線程測試[8167:20874671] 當前剩余票數-> 5
2019-02-21 17:10:40.867402+0800 多線程測試[8167:20874671] 當前剩余票數-> 4
2019-02-21 17:10:40.867879+0800 多線程測試[8167:20874671] 當前剩余票數-> 3
不加鎖時很明顯數據發生了混亂。
iOS中都有哪些鎖?
敲黑板,講重點。
從大的方向講有兩種鎖:
互斥鎖
自旋鎖。
這兩種類型下分別有自己對應的鎖:互斥鎖和自旋鎖的對比:
這兩種鎖的相同點不必多說,都可以避免多線程訪問同一個值發生混亂,重點說一下兩種的不同點:
互斥鎖:如果共享數據已經有其他線程加鎖了,線程會進入休眠狀態等待鎖。一旦被訪問的資源被解鎖, 則等待資源的線程會被喚醒
自旋鎖:如果共享數據已經有其他線程加鎖了,線程會以死循環的方式等待鎖,一旦被訪問的資源被解鎖, 則等待資源的線程會立即執行
自旋鎖的特點:
自旋鎖的性能高于互斥鎖,因為響應速度快
自旋鎖雖然會一直自旋等待獲取鎖,但不會一直占用CPU,超過了操作系統分配的時間片會被強制掛起
自旋鎖如果不能保證所有線程都是同一優先級,則可能造成死鎖。
因為以上的特點,自旋鎖和互斥鎖也有不同的使用場景:
多核處理器情況下: 如果預計線程等待鎖的時間比較短,短到比線程兩次切換上下文的時間還要少的情況下,自旋鎖是更好的選擇。
如果時間比較長,則互斥鎖是比較好的選擇。 單核處理器情況下: 不建議使用自旋鎖。
從詳細來分鎖:
@synchronized
NSLock 對象鎖
NSRecursiveLock遞歸鎖
NSConditionLock 條件鎖
pthread_mutex 互斥鎖(C語言)
dispatch_semaphore 信號量實現加鎖(GCD)
OSSpinLock 自旋鎖
具體使用請移步google。