主要內(nèi)容:
1 GCD隊(duì)列循環(huán)等待镀梭、多讀單寫、組任務(wù)
2 NSOpertaion優(yōu)點(diǎn)
3 NSThread實(shí)現(xiàn)原理
4 常用鎖的區(qū)別
GCD
同步串行
在viewDidLoad中有下面一段代碼
dispatch_sync(dispatch_get_main_queue(), ^{
[self doSomething];
});
很多人說(shuō)這會(huì)造成死鎖。其實(shí)更準(zhǔn)確的說(shuō)法是:主隊(duì)列循環(huán)等待造成死鎖疆液。
主隊(duì)列是一個(gè)串行隊(duì)列偿警,viewDidLoad提交到了主線程執(zhí)還未執(zhí)行完畢负间,此時(shí)再同步提交doSomething到主線程相艇。viewDidLoad被阻塞等待doSomething返回隙姿,而doSomething是后提交的任務(wù),必須等前一個(gè)任務(wù)viewDidLoad執(zhí)行完畢后厂捞,才能執(zhí)行。這就是隊(duì)列循環(huán)等待造成的死鎖队丝。
在viewDidLoad中代碼改為如下
_serialQueue = dispatch_queue_create("thread_name", DISPATCH_QUEUE_SERIAL);
dispatch_sync(_serialQueue, ^{
[self doSomething];
});
這樣會(huì)不會(huì)造成靡馁,隊(duì)列循環(huán)等待呢?答案是:不會(huì)机久。
這里需要注意:只要是同步方式提交臭墨,不管是提交到串行隊(duì)列還是并發(fā)隊(duì)列,都是在當(dāng)前線程執(zhí)行膘盖。
所以,如圖所示不會(huì)造成死鎖胧弛,并且doSomething會(huì)在主線程中執(zhí)行尤误。
同步提交到并發(fā)隊(duì)列
NSLog(@"1");
dispatch_sync(globalQueue, ^{
NSLog(@"2");
dispatch_sync(globalQueue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
并發(fā)隊(duì)列特點(diǎn):提交到隊(duì)列的block可以并發(fā)執(zhí)行。 打印結(jié)果12345
異步提交到并發(fā)隊(duì)列
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
[self performSelector:@selector(printLog) withObject:nil afterDelay:0];
NSLog(@"3");
});
-(void)printLog
{
NSLog(@"2");
}
結(jié)果是:1和3结缚。RunLoop在主線程是自動(dòng)創(chuàng)建的损晤,在子線程中是沒(méi)有創(chuàng)建的。performSelector:withObject:afterDelay: 方法關(guān)鍵是afterDelay相當(dāng)于創(chuàng)建了一個(gè)Timer提交到了RunLoop红竭。等待下一次RunLoop循環(huán)事件時(shí)執(zhí)行尤勋。而子線程中RunLoop根本就沒(méi)有創(chuàng)建。所以printLog也就不會(huì)執(zhí)行茵宪。
[self performSelector:@selector(printLog) withObject:nil];
[self performSelectorOnMainThread:@selector(printLog) withObject:nil waitUntilDone:YES];
請(qǐng)注意上面2個(gè)方法就是一個(gè)普通方法調(diào)用最冰。與帶afterDelay的有本質(zhì)區(qū)別。
dispatch_barrier_async()
提供了一種多讀單寫技術(shù)稀火,讀與讀可以并發(fā)暖哨,讀與寫是互斥的,寫和寫之間是互斥的凰狞。
#import "DataCenter.h"
@interface DataCenter()
{
dispatch_queue_t _concurrent_queue;
//用戶數(shù)據(jù)中心篇裁,可能有多個(gè)線程需要訪問(wèn)
NSMutableDictionary *_dataCenterDict;
}
@end
@implementation DataCenter
-(id)init
{
self = [super init];
if(self){
_concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
_dataCenterDict = [NSMutableDictionary dictionary];
}
return self;
}
-(id)objectForKey:(NSString*)key
{
__block id obj;
//同步讀取指定數(shù)據(jù): 若果是線程A調(diào)用,那么子啊線程A中執(zhí)行服球。 若果是線程B調(diào)用茴恰,那么在線程B中執(zhí)行
//由于是并發(fā)隊(duì)列,可以同時(shí)滿足多個(gè)線程同時(shí)調(diào)用斩熊。
dispatch_sync(_concurrent_queue, ^{
obj = [_dataCenterDict objectForKey:key];
});
return obj;
}
-(void)setObject:(id)obj forKey:(NSString*)key
{
//異步調(diào)用柵欄設(shè)置數(shù)據(jù)
dispatch_barrier_async(_concurrent_queue, ^{
[_dataCenterDict setObject:obj forKey:key];
});
}
NSOperation
優(yōu)點(diǎn)
1 添加依賴任務(wù)
2 任務(wù)執(zhí)行狀態(tài)控制
3 控制最大并發(fā)量
任務(wù)執(zhí)行狀態(tài)控制
isReady : 就緒
isExecuting: 執(zhí)行中
isFinished: 執(zhí)行完成
isCancelled: 已取消
只重寫main()方法往枣,系統(tǒng)控制任務(wù)狀態(tài),以及退出
重寫了start()方法粉渠,需要自己控制任務(wù)狀態(tài)
系統(tǒng)是怎樣移除一個(gè)isFinished=YES的NSOperation的分冈?KVO
NSThread
實(shí)現(xiàn)原理:內(nèi)部創(chuàng)建了一個(gè)pthread線程,當(dāng)執(zhí)行完main函數(shù)后霸株,系統(tǒng)會(huì)自動(dòng)退出雕沉。
鎖
@synchronized
一般在創(chuàng)建單例對(duì)象的時(shí)候使用,保證在多線程環(huán)境下創(chuàng)建對(duì)象唯一
atomic
屬性關(guān)鍵字去件,對(duì)被修飾對(duì)象進(jìn)行原子操作(不負(fù)責(zé)使用)
@property(atomic)NSMutableArray *array;
self.array = [NSMutableArray array]; //保證線程安全
[self.array addObject: obj]; //不保證線程安全
OSSpinLock
循環(huán)等待訪問(wèn)坡椒,不釋放當(dāng)前資源, 專門用于輕量級(jí)訪問(wèn),如+1尤溜,-1操作倔叼。如:引用計(jì)數(shù)
NSRecursiveLock
遞歸鎖可以重入
NSLock
互斥鎖,不可重入宫莱,上鎖解鎖丈攒,成對(duì)出現(xiàn)。
dispatch_semaphore_t
dispatch_semaphore_create(1);
dispatch_semaphore_wait(semphore,DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore)
dispatch_semaphore_create()
struct semaphore {
int value;
List<thread> //相關(guān)線程
}
dispatch_semaphore_wait 檢測(cè)到S.value < 0 ,主動(dòng)阻塞自己
dispatch_semaphore_wait()
{
S.value = S.value - 1;
if S.value < 0 then Block(S.List);
}
dispatch_semaphore_signal 檢查后巡验,去喚醒線程际插。對(duì)于線程來(lái)說(shuō),是一個(gè)被動(dòng)喚醒显设。
dispatch_semaphore_signal()
{
S.value = S.value + 1;
if(S.value <= 0) then wakeup(S.List)
}
總結(jié)
1 怎樣GCD實(shí)現(xiàn)多讀單寫框弛?
2 iOS提供了幾種多線程技術(shù),各自特點(diǎn)是什么敷硅?
3 NSOpertaion對(duì)象在Finished之后是怎樣從queue當(dāng)中移除的功咒?
4 你多用過(guò)那些鎖?結(jié)合實(shí)際談?wù)勀闶窃鯓訉?shí)現(xiàn)的绞蹦?