線程同步:即當有一個線程在對內存進行操做時,其餘線程都不能夠對這個內存地址進行操做,直到該線程完成操做, 其餘線程才能對該內存地址進行操做。面試
因此這裏同步應該不是一塊兒、共同完成的意思,可理解爲協調就是按預約的前後次序進行工做,比如: '不要和我搶了,你先等會我作完了你在作'。算法
線程同步目的爲了多個線程都能很好的工做,合理的訪問系統資源不爭不搶、和諧共處。iOS開發中經常使用的保持線程同步有如下幾種:markdown
經常使用的幾種形式的鎖網絡
- (void)myMethod:(id)anObj
{
@synchronized(anObj)
{
//執行的代碼操做
}
}
複製代碼
經過***synchronized指令
***自動的添加一個互斥鎖,底層經過pthread_mutex實現。經過對一段代碼的使用進行加鎖。其餘試圖執行該段代碼的線程都會被阻塞,直到加鎖線程退出執行該段被保護的代碼段。多線程
當在@synchronized()代碼塊中拋出異常的時候,Objective-C運行時會捕獲到該異常,並釋放信號量,並把該異常從新拋出給下一個異常處理者。架構
一個線程是能夠以遞歸的方式屢次調用***myMethod
***。async
關於參數***anObj
***;oop
做爲一個惟一標識符來標記當前線程加鎖操做必須是個對象類型,因此對於同一個操做不一樣的線程應該用同一個對象,不然沒法起到標記加鎖的做用。 不能爲空nil。學習
常見的基本都是***self
***url
@synchronized(self)
{
//執行的代碼操做
}
複製代碼
self做爲標記符十分常見,可是很明顯會有一個問題:
//方法1
- (void)myMethod1:(id)anObj
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT , 0), ^{
@synchronized(anObj)
{
//執行的代碼操做
}
});
}
//方法2
- (void)myMethod2:(id)anObj
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT , 0), ^{
@synchronized(anObj)
{
//執行的代碼操做
}
});
}
myMethod1(self);
myMethod2(self)</pre>
複製代碼
若是myMethod一、myMethod2沒用任何關係,若是此時執行myMethod1,那麼myMethod2就只能等待其執行完成。因此這種狀況更細的粒度來加鎖,使用各自的對象互不影響更爲合理。
若是多個線程共用一個**lock ,一個線程加鎖後其餘請求加鎖的線程會造成一個等待隊列、按照先進先出的規則等待鎖釋放後再加鎖(待驗證)。
NSCondition對象包含鎖和條件檢測功能,相似於生產者和消費者:消費者消費資源若是沒有就繼續等待,生產者提供資源而後發出信號激活消費者。鎖的做用就是用來保護這一操做防止被其餘線程干擾。
DEMO:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf _user];
});
複製代碼
[weakSelf _produce];
});
複製代碼
-(void)_user{
[condition lock];
while (isWait) {
//等待其餘線程發出信號,[condition signal];
//阻塞當前線程
NSLog(@"等待條件知足");
[condition wait];
}
{
//執行操做
NSLog(@"執行操做");
}
//完成
[condition unlock];
NSLog(@"完成");
}
-(void)_produce{
[condition lock];
isWait = false;
[condition signal];
[condition unlock];
}
複製代碼
輸出結果:
[13781:212898] 等待條件知足
[13781:212898] 執行操做
[13781:212898] 完成</pre>
複製代碼
condition
做爲標識符更容易理解,lockWhenCondition
獲取指定標記的鎖沒有的話就阻塞當前線程,unlockWithCondition:
**釋放指定標記的鎖,等他的線程獲取鎖而後繼續執行操做。使用上比**NSCondition
**更方便些,代碼更簡潔。
用**NSConditionLock
**改寫以上代碼:
-(void)_testConditionLock{
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf _user1];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf _produce1];
});
}
-(void)_user1{
NSLog(@"等待條件知足");
[conditionLock lockWhenCondition:11];
NSLog(@"條件知足了");
{
//執行操做
NSLog(@"執行操做");
}
//完成
[conditionLock unlockWithCondition:0];
NSLog(@"完成");
}
[self _testConditionLock];</pre>
複製代碼
輸出結果:
[7812:120141] 等待條件知足
[7812:120137] 生成條件中...
[7812:120141] 條件知足了
[7812:120141] 執行操做
[7812:120141] 完成</pre>
複製代碼
***OSSpinLock:***自旋鎖,一直輪詢等待時會消耗大量 CPU 資源。
經過建立一個串行隊列,把咱們的操做添加到隊列。
dispatch_queue_t queue = dispatch_queue_create("com.queue.test",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"task 1");
});
dispatch_async(queue, ^{
NSLog(@"task 2");
});
dispatch_async(queue, ^{
NSLog(@"task 3");
});</pre>
複製代碼
感受建立隊列、添加操做到隊列太麻煩,不夠簡潔並且隊列的調度確定佔用很多資源.
經過dispatch_semaphore
信號量實現線程同步
dispatch_semaphore_create(long value);
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);//-1
dispatch_semaphore_signal(dispatch_semaphore_t dsema);//+1</pre>
複製代碼
***dispatch_semaphore_wait
在信號量爲0時會阻塞當前線程,等待dispatch_semaphore_signal
***釋放信號而後繼續執行。
用信號量改寫以上代碼:
-(void)_testSemaphore{
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf _user2];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf _produce2];
});
}
-(void)_user2{
NSLog(@"等待條件知足");
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@"條件知足了");
{
//執行操做
NSLog(@"執行操做");
}
//完成
NSLog(@"完成");
}
-(void)_produce2{
NSLog(@"生成條件中...");
dispatch_semaphore_signal(semaphore);
}
複製代碼
semaphore = dispatch_semaphore_create(0);
NSLog(@"初始化信號0");
[self _testSemaphore];</pre>
複製代碼
輸出:
[9581:159120] 初始化信號0
[9581:159194] 生成條件中... [9581:159195] 等待條件知足 [9581:159195] 條件知足了 [9581:159195] 執行操做 [9581:159195] 完成
經常使用的線程間同步方式就這些了,實際中用的信號量和NSLock比較多。至於其餘的不是由於很差而是由於習慣了,不到很必須的時候我感受都差很少。真正由於其自己所佔用的開銷通常可忽略不計。
實踐前先後後持續了一週的時間,總算進一步加深了認知。寫完了才感受這些知識才是本身的,而後在慢慢吸取、消化,才能伴隨咱們一步步的走向強大。
將來的路很長,不知道會走多遠,只想走好腳下的每一步!
做爲一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是個人iOS交流圈: 無論你是小白仍是大牛歡迎入駐!! 分享內容包括跳槽面試寶典、逆向安防、算法、架構設計、多線程,網絡進階,還有底層、音視頻、Flutter等等......
本身根據梳理網絡來的的開發經驗總結的學習方法,無償分享給你們。更多資源,須要的話均可以自行來獲取下載。 +裙:196800191、 或者是+ WX(XiAZHiGardenia)免費獲取! 獲取面試資料 簡歷模板 一塊兒交流技術資源集合
over.over.