1.進程與線程
進程是具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運行活動涎嚼,是操作系統(tǒng)進行資源分配和調(diào)度的一個獨立單位轿塔。線程是進程的一個實體,是CPU調(diào)度和分派的基本單位配并,是比進程更小的能獨立運行的基本單位。任務(wù)(task)用于指代抽象的概念,表示需要執(zhí)行工作高镐,具體可以是一個函數(shù)或者一個block溉旋。
2.多線程實現(xiàn)方式
- POSIX線程:簡稱Pthreads,是線程的POSIX標(biāo)準(zhǔn)嫉髓,該標(biāo)準(zhǔn)定義了創(chuàng)建和操作線程的一套API观腊,是由C語言實現(xiàn)的邑闲,例如pthreadcreate()函數(shù)可以創(chuàng)建線程,pthreadexit()函數(shù)可以終止當(dāng)前線程梧油,pthreadmutexinit()函數(shù)可以初始化互斥鎖等等监憎,使用這種方式操作線程需要扎實的C編程功底以及對系統(tǒng)底層工作機制的認識。
- NSThread類:線程婶溯,此種方式是輕量級的線程機制,但需要自行管理線程的生命周期偷霉,線程同步等問題迄委,同步鎖會產(chǎn)生系統(tǒng)開銷。
- NSOperationQueue類:執(zhí)行隊列类少,優(yōu)點是不需要關(guān)心線程管理叙身,數(shù)據(jù)同步的事情,可以把精力放在線程需要執(zhí)行的操作上硫狞。
- GCD:Grand Central Dispatch信轿,是蘋果公司開發(fā)的技術(shù),以優(yōu)化的應(yīng)用程序支持多核心處理器和其他的對稱多處理系統(tǒng)的系統(tǒng)残吩。這建立在任務(wù)并行執(zhí)行的線程池模式的基礎(chǔ)上的财忽。它首次發(fā)布在Mac OS X 10.6,iOS 4及以上也可以使用泣侮,該技術(shù)是取代上述技術(shù)的技術(shù)即彪。
3.NSThread
輕量級最低,相對簡單活尊,需要手動管理所有的線程活動(生命周期隶校,休眠,同步等)線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷蛹锰。
(1)創(chuàng)建線程
a.//類方法創(chuàng)建
[NSThread detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument];
b.//對象方法創(chuàng)建
NSThread *thread = [[NSThread alloc] initWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument];
[thread start];
(2)線程同步
a.NSLock
b.NSCondition
c.@synchronized代碼塊
4.NSOperation
自帶線程周期管理深胳,可只關(guān)注自己處理邏輯
NSOperation是面向?qū)ο蟮某橄箢悾瑢崿F(xiàn)只能是其子類(NSInvocationOperation和NSBlockOperation)铜犬,對象需要添加到NSOperationQueue隊列里執(zhí)行
a.同步執(zhí)行
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(foo) object:nil];
[operation1 start];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
}];
[operation2 start];
b.異步執(zhí)行
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(foo) object:nil];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];
//如果需要控制隊列中線程的數(shù)量舞终,可以使用下面的方式:
[queue setMaxConcurrentOperationCount:5];
5.GCD
GCD全稱為Grand Central Dispatch,是libdispatch的市場名稱癣猾,而libdispatch是Apple的一個庫权埠,其為并發(fā)代碼在iOS和OS X的多核硬件上執(zhí)行提供支持。確切地說GCD是一套低層級的C API煎谍,通過 GCD攘蔽,開發(fā)者只需要向隊列中添加一段代碼塊(block或C函數(shù)指針),而不需要直接和線程打交道呐粘。GCD在后端管理著一個線程池满俗,它不僅決定著你的代碼塊將在哪個線程被執(zhí)行转捕,還根據(jù)可用的系統(tǒng)資源對這些線程進行管理。這樣通過GCD來管理線程唆垃,從而解決線程被創(chuàng)建的問題五芝。
異步隊列 VS 同步隊列
dispatch_async(queue,block) async 異步隊列,dispatch_async 函數(shù)會立即返回, block會在后臺異步執(zhí)行辕万。 dispatch_sync(queue,block) sync 同步隊列枢步,dispatch_sync 函數(shù)不會立即返回,及阻塞當(dāng)前線程,等待 block同步執(zhí)行完成渐尿。
//例:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL * url = [NSURL URLWithString:@"http://image.jpg"];
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc]initWithData:data];
if (data != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
}
});
串行隊列和并行隊列
串行隊列就是單條線程中醉途,任務(wù)挨個處理,主線程本身就是串行隊列砖茸,一條鐵路多個火車排隊走隘擎。 并行隊列就是多條線程,多個任務(wù)同時處理凉夯,多條鐵軌多個火車同時走货葬。
//串行隊列
dispatch_queue_t queue = dispatch_queue_create("baobao", DISPATCH_QUEUE_SERIAL);
//并行隊列
dispatch_queue_t queue = dispatch_queue_create("baobao", DISPATCH_QUEUE_CONCURRENT);
//系統(tǒng)默認有一條并行隊列
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//系統(tǒng)默認有一條串行隊列
dispatch_queue_t mainQ = dispatch_get_main_queue();
私有隊列和全局隊列
//私有隊列
dispatch_queue_t queue = dispatch_queue_create("baobao", NULL);
//全局隊列有且唯一,統(tǒng)一調(diào)度劲够,優(yōu)化資源
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
使用隊列
// 提交一個block
dispatch_async(queue, ^{
//...
dispatch_async(dispatch_get_main_queue(), ^{
//刷新UI
});
});
//通常的震桶,無特殊要求的,分線程一律采用global_queue統(tǒng)一調(diào)度,優(yōu)先級無特殊要求的采用Default即可征绎。所謂的優(yōu)先級分配是指待分配任務(wù)中高優(yōu)先級先行尼夺,而對于已進入線程的任務(wù),不會受到后續(xù)任務(wù)的優(yōu)先級影響炒瘸。
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
組任務(wù)
(1)dispatch_group_async 可以實現(xiàn)監(jiān)聽一組任務(wù)是否完成淤堵,完成后得到通知執(zhí)行其他的操作。這個方法很有用顷扩,比如你執(zhí)行三個下載任務(wù)拐邪,當(dāng)三個任務(wù)都下載完成后你才通知界面說完成的了。例:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"group1 [NSThread sleepForTimeInterval:3];");
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"group2 [NSThread sleepForTimeInterval:2];");
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"group3 [NSThread sleepForTimeInterval:1];");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"main thread.");
});
執(zhí)行結(jié)果:
**2017-01-03 10:29:50.128 ****簡書****[960:412447] group3 [NSThread sleepForTimeInterval:1];**
**2017-01-03 10:29:51.130 ****簡書****[960:412448] group2 [NSThread sleepForTimeInterval:2];**
**2017-01-03 10:29:52.128 ****簡書****[960:412450] group1 [NSThread sleepForTimeInterval:3];**
**2017-01-03 10:29:52.129 ****簡書****[960:412106] main thread.**
(2)dispatch_barrier_async是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行隘截,而且它后面的任務(wù)等它執(zhí)行完成之后才會執(zhí)行扎阶,例:
dispatch_queue_t queue = dispatch_queue_create("baobao", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"dispatch_async1");
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"dispatch_async2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async");
[NSThread sleepForTimeInterval:1];
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"dispatch_async3");
});
執(zhí)行結(jié)果:
**2017-01-03 10:36:38.500 ****簡書****[1033:454725] dispatch_async2**
**2017-01-03 10:36:38.500 ****簡書****[1033:454746] dispatch_async1**
**2017-01-03 10:36:38.500 ****簡書****[1033:454746] dispatch_barrier_async**
**2017-01-03 10:36:42.511 ****簡書****[1033:454746] dispatch_async3**
//如果使用dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
執(zhí)行結(jié)果:
**2017-01-03 10:39:45.198 ****簡書****[1059:477846] dispatch_barrier_async**
**2017-01-03 10:39:48.199 ****簡書****[1059:477847] dispatch_async2**
**2017-01-03 10:39:48.199 ****簡書****[1059:477849] dispatch_async1**
**2017-01-03 10:39:48.199 ****簡書****[1059:477894] dispatch_async3**
//說明dispatch_barrier_async的順序執(zhí)行還是依賴queue的類型,必需要queue的類型為dispatch_queue_create創(chuàng)建的婶芭,而且attr參數(shù)值必需是DISPATCH_QUEUE_CONCURRENT類型东臀,前面兩個非dispatch_barrier_async的類型的執(zhí)行是依賴其本身的執(zhí)行時間的,如果attr如果是DISPATCH_QUEUE_SERIAL時犀农,那就完全是符合Serial queue的FIFO特征了惰赋。
線程批處理
dispatch_apply的作用是在一個隊列(串行或并行)上“運行”多次block,其實就是簡化了用循環(huán)去向隊列依次添加block任務(wù)。
//創(chuàng)建異步串行隊列
dispatch_queue_t queue = dispatch_queue_create("baobao", DISPATCH_QUEUE_SERIAL);
//運行block3次
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
});
NSLog(@"After apply");
執(zhí)行結(jié)果:
**2017-01-03 10:46:59.132 ****簡書****[1088:522375] apply loop: 0**
**2017-01-03 10:46:59.133 ****簡書****[1088:522375] apply loop: 1**
**2017-01-03 10:46:59.133 ****簡書****[1088:522375] apply loop: 2**
**2017-01-03 10:46:59.133 ****簡書****[1088:522375] After apply**
dispatch_once函數(shù)
保證整個應(yīng)用程序生命周期中某段代碼只被執(zhí)行一次赁濒!dispatch_once_t必須是全局或static變量轨奄,非全局或非static的dispatch_once_t變量在使用時會產(chǎn)生BUG
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
掛起和恢復(fù)隊列
dispatch_queue_t queue = dispatch_queue_create("baobao", DISPATCH_QUEUE_SERIAL);
//提交第一個block,延時3秒打印拒炎。
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"After 3 seconds...");
});
//提交第二個block挪拟,也是延時3秒打印
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"After 3 seconds again...");
});
//延時一秒
NSLog(@"sleep 1 second...");
[NSThread sleepForTimeInterval:1];
//掛起隊列
NSLog(@"suspend...");
dispatch_suspend(queue);
//延時5秒
NSLog(@"sleep 5 second...");
[NSThread sleepForTimeInterval:5];
//恢復(fù)隊列
NSLog(@"resume...");
dispatch_resume(queue);
//執(zhí)行結(jié)果:
**2017-01-03 10:59:51.390 ****簡書****[1123:585605] sleep 1 second...**
**2017-01-03 10:59:52.391 ****簡書****[1123:585605] suspend...**
**2017-01-03 10:59:52.392 ****簡書****[1123:585605] sleep 5 second...**
**2017-01-03 10:59:54.395 ****簡書****[1123:585650] After 3 seconds...**
**2017-01-03 10:59:57.393 ****簡書****[1123:585605] resume...**
**2017-01-03 11:00:00.393 ****簡書****[1123:585650] After 3 seconds again...**