iOS學(xué)習(xí)之多線程與GCD

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...**
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市击你,隨后出現(xiàn)的幾起案子玉组,更是在濱河造成了極大的恐慌,老刑警劉巖丁侄,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惯雳,死亡現(xiàn)場離奇詭異,居然都是意外死亡绒障,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門捍歪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來户辱,“玉大人,你說我怎么就攤上這事糙臼÷洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵变逃,是天一觀的道長必逆。 經(jīng)常有香客問我,道長揽乱,這世上最難降的妖魔是什么名眉? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮凰棉,結(jié)果婚禮上损拢,老公的妹妹穿的比我還像新娘。我一直安慰自己撒犀,他們只是感情好福压,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著或舞,像睡著了一般荆姆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上映凳,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天胆筒,我揣著相機與錄音,去河邊找鬼诈豌。 笑死腐泻,一個胖子當(dāng)著我的面吹牛决乎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播派桩,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼构诚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铆惑?” 一聲冷哼從身側(cè)響起范嘱,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎员魏,沒想到半個月后丑蛤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡撕阎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年受裹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虏束。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡棉饶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镇匀,到底是詐尸還是另有隱情照藻,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布汗侵,位于F島的核電站幸缕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晰韵。R本人自食惡果不足惜发乔,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雪猪。 院中可真熱鬧列疗,春花似錦、人聲如沸浪蹂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坤次。三九已至古劲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缰猴,已是汗流浹背产艾。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闷堡。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓隘膘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杠览。 傳聞我的和親對象是個殘疾皇子弯菊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容