1、概述編程
(1) Run Loop提供了一種異步執行代碼的機制,不能並行執行任務。網絡
(2) 在主隊列中,Main Run Loop直接配合任務的執行,負責處理UI事件、計時器,以及其它內核相關事件。多線程
(3) Run Loop的主要目的是保證程序執行的線程不會被系統終止。併發
Run Loop的工做特色:異步
(1) 當有事件發生時,Run Loop會根據具體的事件類型通知應用程序作出響應。async
(2) 當沒有事件發生時,Run Loop會進入休眠狀態,從而達到省電的目的。oop
(3) 當事件再次發生時,Run Loop會被從新喚醒,處理事件。性能
主線程和其餘線程中的Run Loop:atom
iOS程序的主線程默認已經配置好了Run Loop,其餘線程默認狀況下沒有設置Run Loop。spa
通常在開發中不多會主動建立RunLoop,而一般會把事件添加到RunLoop中。
loop示意圖:
2、UIApplication中的Run Loop
3、多線程中的循環引用
若是self對象持有操做對象的引用,同時操做對象當中又直接訪問了self時,纔會形成循環引用。
單純在操做對象中使用self不會形成循環引用。
注意:此時不能使用(weakSelf)
4、多線程中的資源共享
併發編程中許多問題的根源就是在多線程中訪問共享資源。資源能夠是一個屬性、一個對象、網絡設備或者一個文件等。
在多線程中任何一個共享的資源均可能是一個潛在的衝突點,必須精心設計以防止這種衝突的發生。
資源共享示例:
5、互斥鎖(@synchronized)
互斥鎖使用注意:
(1)加互斥鎖,在共享資源的「讀」「寫」範圍添加互斥鎖
(2)要讓鎖的範圍儘量小!
(3)資源搶奪作簡單的作法就是使用互斥鎖@synchronized
(4)使用互斥鎖,會變慢,互斥鎖的代價十分高昂!
加上互斥鎖就可使一個資源在同一時間只能被一個線程訪問,只有這個資源被這個線程用完後其餘線程才能訪問。
互斥鎖用法:
@synchronized(self) {
//線程操做
}
例如:
@interface MJViewController ()
@property (weak, nonatomic) IBOutlet UITextView *infoText;
// 票數,若使用原子鎖,只需在互斥鎖的基礎上把下面nonatomic改成atomic便可
@property (nonatomic, assign) NSInteger tickets;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
// 賣票循環,一直賣完爲止
- (void)doSaleLoop:(NSString *)opName
{
// 全部線程進入均可以循環賣票
while (YES) {
@synchronized(self) {
if (self.tickets > 0) {
--self.tickets;
NSLog(@"剩餘票數 %d - %@ - %@", self.tickets, opName, [NSThread currentThread]);
} else {
break;
}
}
//-----------------------------------------
// 模擬休眠,跟資源搶奪無關,不用放在鎖裏
if ([opName isEqualToString:@"OP 1"]) {
[NSThread sleepForTimeInterval:1.0f];
} else {
[NSThread sleepForTimeInterval:0.3f];
}
}
}
#pragma mark 模擬多人賣票
#pragma mark GCD實現
- (IBAction)doSale:(id)sender
{
// 作多線程開始時,永遠不要相信一次運行的結果
self.tickets = 20;
// 1. 隊列
dispatch_queue_t q = dispatch_queue_create("sale", DISPATCH_QUEUE_CONCURRENT);
// 2. 添加任務
dispatch_async(q, ^{
[self doSaleLoop:@"OP 1"];
});
dispatch_async(q, ^{
[self doSaleLoop:@"OP 2"];
});
dispatch_async(q, ^{
[self doSaleLoop:@"OP 3"];
});
dispatch_async(q, ^{
[self doSaleLoop:@"OP 4"];
});
}
@end
【備註】在iOS中還有一種鎖的功能,原子鎖 —— 多讀單寫的鎖(128位自旋鎖),也會消耗性能。
原子鎖只保護寫入時的數據正確,而讀取不負責。
對於要寫入的資源,保護「寫入數據」的正確性重要,仍是讀取的準確性重要!
若是隻是開發單寫多讀的功能,只須要使用原子鎖便可。
@synchronized 性能消耗很是的大,蘋果官方不建議使用。
在實際開發中,不要去搶奪資源!
*** 併發編程最主要的目的是提升性能,讓更多的代碼同時運行,達到併發運行,提升總體性能的目的!
*** 手機開發最主要的是流暢,並行,至於資源搶奪的功能開發是屬於服務端的範疇!