iOS 與多線程

· NSThread 可以直接操作線程
· GCD: Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的較新的解決方法狸捅。它主要用于優(yōu)化應用程序以支持多核處理器以及其他對稱多處理系統(tǒng)茅撞。它是一個在線程池模式的基礎上執(zhí)行的并行任務成畦。
· NSOperation 在GCD之上的封裝,更適合添加操作之間的依賴關(guān)系。

NSThread 常用點

  1. setName 可以定義線程的名字悯搔,方便跟蹤和調(diào)試
  2. [NSThread currentThread] 可以看當前操作的線程
 NSThread *thread = [[NSThread alloc] initWithTarget:self
                                               selector:@selector(threadTest)
                                                 object:nil];
[thread setName:@"EasyIOSThread"];
[thread start];
name方便調(diào)試

3.最厲害的一點思灌,他可以直接讓線程死亡俺叭,也就是當前沒做完的操作立馬終止

[thread exit];

GCD

  1. dispatch queue

任務間執(zhí)行的方式
DISPATCH_QUEUE_CONCURRENT 并行
DISPATCH_QUEUE_SERIAL_INACTIVE 串行
同步異步
dispatch_async 開啟異步隊列,具備開啟線程的能力
dispatch_sync 開啟同步隊列泰偿,不會開辟新的線程

1.并行異步

dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"gcd1.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"gcd2.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"gcd3.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"gcd4.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"gcd5.queue %@",[NSThread currentThread]);
        }
    });

執(zhí)行結(jié)果

 1.gcd1 gcd2 gcd3 gcd4  gcd5 會隨機的打印熄守,也就說是同時執(zhí)行
 2.[NSThread currentThread] 不是主線程,且有多個線程

dispatch_async 會從當前的線程切換到新的線程甜奄, DISPATCH_QUEUE_CONCURRENT 并發(fā)執(zhí)行柠横,異步并發(fā)的線程會開啟多條線程,線程的數(shù)量由任務數(shù)量课兄、系統(tǒng)可分配線程數(shù)共同決定

串行異步

dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd1.queue");
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd2.queue");
        }
    });

執(zhí)行結(jié)果

1.gcd1 打印完成后才接著打印gcd2
2.不是在主線程牍氛,線程打印輸出 <NSThread: 0x60400047f500>{number = 8, name = null}

并行同步

dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd1.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd2.queue %@",[NSThread currentThread]);
        }
    });

串行同步

dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd1.queue %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int index = 0; index < 100; index++) {
            NSLog(@"gcd2.queue %@",[NSThread currentThread]);
        }
    });

執(zhí)行結(jié)果

1. 都是在當前線程執(zhí)行紫皇,調(diào)試的時候是在主線程睦刃,所以打印顯示的是 mian 線程
2. 任務是順序打印的

因為是同步任務,所以不會從線程池獲取線程隙姿,只是使用當前線程,任務就只能一個執(zhí)行完成后在執(zhí)行其他的任務

小結(jié)

隊列執(zhí)行方式
串行隊列是一個任務一個任務順序執(zhí)行
并行隊列是可以同時調(diào)度多個任務

任務開啟方式
同步執(zhí)行:不會到線程池里邊獲取子線程
異步執(zhí)行:只要有任務唉擂,就會去獲取新線程 【主隊列只有一條線程餐屎,除外】

兩個重要的隊列

dispatch_get_global_queue 全局隊列,他是一個并發(fā)的隊列
dispatch_get_main_queue() 主隊列玩祟,他是串行的隊列【有且只有主線程】

for (int index = 0; index < 5; index ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"dispatch_async %@ %d",[NSThread currentThread],index);
        });
        
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"dispatch_sync %@ %d",[NSThread currentThread],index);
        });
        
        NSLog(@"come here %d",index);
    }

運行結(jié)果

1. dispatch_sync 是在當前線程執(zhí)行的 線程打印為<NSThread: 0x604000072980>{number = 1, name = main}
2. dispatch_async 不是在當前線程執(zhí)行的腹缩,線程打印為 <NSThread: 0x60000047ed00>{number = 3, name = (null) 和 <NSThread: 0x604000660340>{number = 4, name = (null)
3. come here 的調(diào)用順序始終在dispatch_sync之后
4. dispatch_sync 和 dispatch_async 打印隨機,也就是說主線程和其他線程交替執(zhí)行

單看 dispatch_async

異步的多個dispatch_get_global_queue 可以在多條線程并發(fā)執(zhí)行
同步的只能在當前線程執(zhí)行 (come here 總是在 dispatch_sync)

dispatch_get_main_queue() 常用地方 - 從別的線程回到主線程

// to main
dispatch_async(dispatch_get_main_queue(), ^{
            
 });

GCD 線程切換注意點:不能用同步的方式切換到同一個串行隊列
例如:

// current queue is main queue
dispatch_sync(dispatch_get_main_queue(), ^{
            
 });
 // 如果是非主隊列也如此
dispatch_queue_t queue = dispatch_queue_create("gcd", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{
        
        NSLog(@"外邊的1 %@",[NSThread currentThread]);
        dispatch_sync(queue, ^{
            NSLog(@"里邊的 %@",[NSThread currentThread]);
            
        });
        NSLog(@"外邊的2 %@",[NSThread currentThread]);
        
    });
 //但是并發(fā)的隊列不會死鎖
 dispatch_queue_t queue = dispatch_queue_create("gcd", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
        
        NSLog(@"外邊的1 %@",[NSThread currentThread]);
        dispatch_sync(queue, ^{
            NSLog(@"里邊的 %@",[NSThread currentThread]);
            
        });
        NSLog(@"外邊的2 %@",[NSThread currentThread]);
        
  });

原因

  1. 串行隊列的任務是順序執(zhí)行的空扎,需要等到前面已經(jīng)入隊的任務執(zhí)行完然后在執(zhí)行后續(xù)任務
  2. 同步執(zhí)行是在當前的隊列立馬執(zhí)行任務
  3. 在串行的隊列里邊執(zhí)行同步任務藏鹊,這個同步任務是在隊列的中間插入的,從隊列的執(zhí)行順序看转锈,這個同步任務需要等到他前面的任務執(zhí)行完成后在執(zhí)行盘寡,但是同步任務自身又是不能等待的,他要立馬執(zhí)行撮慨。兩者就產(chǎn)生了死鎖竿痰。
  4. 從dispatch_sync(dispatch_get_main_queue(), ^{}); 產(chǎn)生死鎖我們也可以確定主隊列是串行的

重要方法 1. dispatch_group_t group, 在dispatch_group_notify 可以讓任務完成后返回

 dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("download_queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        for (int index = 0; index < 3; index ++) {
            NSLog(@"first task %d",index);
        }
    });
    dispatch_group_async(group, queue, ^{
        for (int index = 0; index < 3; index ++) {
            NSLog(@"second task %d",index);
        }
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"task finish");
    });
[第280行]: second task 0
[第275行]: first task 0
[第280行]: second task 1
[第275行]: first task 1
[第280行]: second task 2
[第275行]: first task 2
[第284行]: task finish

dispatch_barrier_sync 和 dispatch_barrier_async 柵欄函數(shù)

 dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"11111");
        }
    });
    
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"22222");
        }
    });
    
    dispatch_barrier_sync(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"dispatch_barrier_sync %@",[NSThread currentThread]);
        }
        return ;
    });
    NSLog(@"----");
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"33333");
        }
    });
    dispatch_async(queue, ^{
        for (int index = 0; index < 10; index++) {
            NSLog(@"44444");
        }
    });

執(zhí)行結(jié)果

1. 1111 和 2222 隨機打印
2. 打印 dispatch_barrier_sync
3. 打印 ----
4. 33333 和  44444 隨機打印

小結(jié)
dispatch_barrier_sync 和 dispatch_barrier_async 都會將前后的任務隔開,并且要等到前邊的任務執(zhí)行完后砌溺,在執(zhí)行柵欄里邊的任務影涉,然后執(zhí)行后邊的任務。
區(qū)別是 sync 是同步的抚吠, 也就是說當前的線程執(zhí)行到dispatch_barrier_sync 時會去執(zhí)行這個隊列里的任務【如果當前隊列和當前的線程是一個常潮,會死鎖】 dispatch_async 是異步的,不需要切換到該隊列去執(zhí)行

NSOperation 可以很方便管理任務之間的依賴

    self.queue = [[NSOperationQueue alloc] init];
    [self.queue setName:@"qk.queue.com"];
    
    //第一條線
    NSInvocationOperation *firstOperation
    = [[NSInvocationOperation alloc]
       initWithTarget:self
       selector:@selector(firstStep)
       object:nil];
    
    [firstOperation setName:@"qk.queue.firstOperation"];
    
    //第二條線
    NSInvocationOperation *secondOperation
    = [[NSInvocationOperation alloc] initWithTarget:self
                                           selector:@selector(secondStep)
                                             object:nil];
    
    [secondOperation setName:@"qk.queue.secondOperation"];
    
    
    //前面的要在后邊的執(zhí)行完成后才能夠執(zhí)行
    [secondOperation addDependency:firstOperation];
    
    //如果沒有添加依賴關(guān)系 operation 會并發(fā)執(zhí)行
    [self.queue addOperation:secondOperation];
    [self.queue addOperation:firstOperation];
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末楷力,一起剝皮案震驚了整個濱河市喊式,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌萧朝,老刑警劉巖岔留,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異检柬,居然都是意外死亡献联,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門何址,熙熙樓的掌柜王于貴愁眉苦臉地迎上來里逆,“玉大人,你說我怎么就攤上這事用爪≡海” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵偎血,是天一觀的道長诸衔。 經(jīng)常有香客問我盯漂,道長,這世上最難降的妖魔是什么笨农? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任就缆,我火速辦了婚禮,結(jié)果婚禮上谒亦,老公的妹妹穿的比我還像新娘竭宰。我一直安慰自己,他們只是感情好诊霹,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布羞延。 她就那樣靜靜地躺著,像睡著了一般脾还。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上入愧,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天鄙漏,我揣著相機與錄音,去河邊找鬼棺蛛。 笑死怔蚌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的旁赊。 我是一名探鬼主播桦踊,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼终畅!你這毒婦竟也來了籍胯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤离福,失蹤者是張志新(化名)和其女友劉穎杖狼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妖爷,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蝶涩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了絮识。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绿聘。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖次舌,靈堂內(nèi)的尸體忽然破棺而出熄攘,到底是詐尸還是另有隱情,我是刑警寧澤垃它,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布鲜屏,位于F島的核電站烹看,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏洛史。R本人自食惡果不足惜惯殊,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望也殖。 院中可真熱鬧土思,春花似錦、人聲如沸忆嗜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捆毫。三九已至闪湾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绩卤,已是汗流浹背途样。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留濒憋,地道東北人何暇。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像凛驮,于是被迫代替她去往敵國和親裆站。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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