多線程 之 GCD

1酿炸、同步和異步瘫絮、并發(fā)隊(duì)列和串行隊(duì)列

一般在開發(fā)中,我們使用GCD比較的多填硕,所以就按照GCD來詳細(xì)解釋一下多線程中的同步和異步麦萤、并發(fā)隊(duì)列和串行隊(duì)列鹿鳖。

在上一篇文章中,我們也了解到:

  • GCD中有2個(gè)用來執(zhí)行任務(wù)的函數(shù):
    用同步的方式執(zhí)行任務(wù):
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    用異步的方式執(zhí)行任務(wù):
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

  • GCD的隊(duì)列可以分為2大類型:
    并發(fā)隊(duì)列(Concurrent Dispatch Queue)
    可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
    并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
    串行隊(duì)列(Serial Dispatch Queue)
    讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后壮莹,再執(zhí)行下一個(gè)任務(wù))

總結(jié)來說就是:
同步和異步主要影響:能不能開啟新的線程
同步:在當(dāng)前線程中執(zhí)行任務(wù)翅帜,不具備開啟新線程的能力
異步:在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
串行:一個(gè)任務(wù)執(zhí)行完畢后命满,再執(zhí)行下一個(gè)任務(wù)

他們組合起來的效果:
屏幕快照 2018-11-25 下午11.52.08.png
2涝滴、實(shí)例解析
//    手動(dòng)生成的串行隊(duì)列,一個(gè)一個(gè)的去執(zhí)行
//    如果是sync(同步的)胶台,不會(huì)開啟新線程歼疮,那就在主線程中執(zhí)行,并且安照順序執(zhí)行dispatch_sync中的任務(wù)概作,再執(zhí)行“完成”
//    如果是async(異步的),會(huì)開啟新線程腋妙,在子線程中執(zhí)行默怨,但是只開啟一條新線程,先執(zhí)行“完成”信息讯榕,再執(zhí)行安照順序執(zhí)行dispatch_async中的任務(wù)
    dispatch_queue_t queue = dispatch_queue_create("cn.itcast.serialA", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        for (int i = 0; i<10; i++) {
            NSLog(@"執(zhí)行任務(wù)1 %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i<10; i++) {
            NSLog(@"執(zhí)行任務(wù)2 %@",[NSThread currentThread]);
        }
    });  
    NSLog(@"完成");
    //并發(fā)隊(duì)列,任務(wù)可以一起并行執(zhí)行
    //如果是sync(同步的)匙睹,就不會(huì)開啟新的線程愚屁,還是會(huì)在主線程中一個(gè)個(gè)的串行執(zhí)行,先安照順序執(zhí)行dispatch_sync中的任務(wù)痕檬,再執(zhí)行“完成”
    //如果是async(異步的)霎槐,會(huì)開啟新的線程,就會(huì)不同的線程中并發(fā)的執(zhí)行任務(wù)梦谜,先執(zhí)行完成丘跌,在并發(fā)執(zhí)行異步任務(wù)
    dispatch_queue_t queue =  dispatch_queue_create("cn.fichfit.concurrentQueueA", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue, ^{
        for (int i = 0; i<10; i++) {
            NSLog(@"執(zhí)行任務(wù)1  %@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i=0; i<10; i++) {
            NSLog(@"執(zhí)行任務(wù)2 %@",[NSThread currentThread]);
        }
    });
    NSLog(@"完成");
    //主隊(duì)列,肯定不會(huì)開啟自線程
    //如果是sync(同步的)唁桩,會(huì)報(bào)錯(cuò):因?yàn)樵谥骶€程上,遇到dispatch_sync闭树,會(huì)立即執(zhí)行同步任務(wù),但是執(zhí)行同步任務(wù)之前又要求執(zhí)行“完成”任務(wù)荒澡,互相等待报辱,所以就會(huì)卡住
    //如果是async(異步的),會(huì)在主線程中单山,串行執(zhí)行任務(wù)碍现,先執(zhí)行"完成",然后執(zhí)行異步任務(wù)
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        for (int i = 0; i<10; i++) {
            NSLog(@"執(zhí)行任務(wù)1 %@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i<10;i++) {
            NSLog(@"執(zhí)行任務(wù)2 %@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"完成");
3、總結(jié)
  • <1>看下面的例子米奸,看會(huì)不會(huì)產(chǎn)生死鎖現(xiàn)象昼接?
//sync會(huì)死鎖
//async不會(huì)死鎖
-(void)test1{
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}
//block1處會(huì)死鎖
-(void)test2{
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{//block0
        NSLog(@"任務(wù)2");
        dispatch_sync(queue, ^{//block1,在執(zhí)行完任務(wù)2后,又向隊(duì)列中加入一個(gè)同步任務(wù)3悴晰,所以會(huì)堵塞住任務(wù)4的執(zhí)行辩棒,因?yàn)闀?huì)產(chǎn)生卡住
            NSLog(@"任務(wù)3");
        });
        NSLog(@"任務(wù)4");
    });
    NSLog(@"任務(wù)5");
}
//block1處不會(huì)死鎖:如果當(dāng)所處的隊(duì)列不一樣時(shí),不會(huì)產(chǎn)生死鎖
-(void)interview3{
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("myQueue33", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{//block0
        NSLog(@"任務(wù)2");
        dispatch_sync(queue2, ^{//block1
            NSLog(@"任務(wù)3");
        });
        NSLog(@"任務(wù)4");
        
    });
    NSLog(@"任務(wù)5");
}

總結(jié)一下就是:
使用sync函數(shù)當(dāng)前串行隊(duì)列中添加任務(wù),會(huì)卡住當(dāng)前的串行隊(duì)列(產(chǎn)生死鎖)

  • <2>看下面的例子一睁,觀察打印情況
-(void)test{
    NSLog(@"1");
    dispatch_queue_t queue = dispatch_queue_create(0, 0);
    dispatch_async(queue, ^{
        [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
    });
    NSLog(@"3");
}

-(void)run{
    NSLog(@"2");
}

打印結(jié)果:(不打印 run中的內(nèi)容)
================================================
1
3

原因是:
主線程的 RunLoop 對(duì)象系統(tǒng)自動(dòng)幫助我們創(chuàng)建好了钻弄,而子線程的 RunLoop對(duì)象需要我們主動(dòng)創(chuàng)建和維護(hù)者吁。
performSelector:withObject:afterDelay:的本質(zhì)是往Runloop中添加定時(shí)器,子線程默認(rèn)沒有啟動(dòng)Runloop复凳,所以不會(huì)執(zhí)行run方法瘤泪。

如下例子則可以保證self.thread處于激活狀態(tài)育八,test方法也會(huì)執(zhí)行。

@interface ViewController ()
@property(nonatomic,strong)NSThread *thread;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"111");
        //這里并沒有runloop髓棋,但是NSLog能夠執(zhí)行
        //是因?yàn)椴⒉皇侵骶€程所有的事情都交給runloop去做,如是大多數(shù)的事情交給runloop去做按声,比如UI的刷新膳犹、點(diǎn)擊事件的處理签则、performSelector
        
        
        //如果這里不加上下面的兩句,self.thread就會(huì)失活
        //因?yàn)榫€程的任務(wù)一旦執(zhí)行完畢渐裂,生命周期就會(huì)結(jié)束豺旬,無法再使用
        //所以說,NSRunLoop就是為了保持使線程保持激活狀態(tài)
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    }];
    [self.thread start];
}


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //在self.thread線程上執(zhí)行
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:YES];
}

-(void)test{
    NSLog(@"在self.thread線程上執(zhí)行任務(wù)");
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柒凉,一起剝皮案震驚了整個(gè)濱河市族阅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扛拨,老刑警劉巖耘分,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绑警,居然都是意外死亡求泰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門计盒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渴频,“玉大人,你說我怎么就攤上這事北启〔防剩” “怎么了拔第?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)场钉。 經(jīng)常有香客問我蚊俺,道長(zhǎng),這世上最難降的妖魔是什么逛万? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任泳猬,我火速辦了婚禮,結(jié)果婚禮上宇植,老公的妹妹穿的比我還像新娘得封。我一直安慰自己,他們只是感情好指郁,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布忙上。 她就那樣靜靜地躺著,像睡著了一般闲坎。 火紅的嫁衣襯著肌膚如雪疫粥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天箫柳,我揣著相機(jī)與錄音手形,去河邊找鬼啥供。 笑死悯恍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伙狐。 我是一名探鬼主播涮毫,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼贷屎!你這毒婦竟也來了罢防?” 一聲冷哼從身側(cè)響起唉侄,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎属划,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體同眯,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年硅确,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菱农。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蛉腌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烙丛,我是刑警寧澤羔味,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站忘蟹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏媚值。R本人自食惡果不足惜护糖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嫡良。 院中可真熱鬧,春花似錦寝受、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浪藻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爱葵,已是汗流浹背反浓。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工雷则, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人月劈。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓藤乙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親坛梁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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

  • 1. GCD簡(jiǎn)介 什么是GCD呢拴念?我們先來看看百度百科的解釋簡(jiǎn)單了解下概念 引自百度百科:Grand Centra...
    千尋_544f閱讀 369評(píng)論 0 0
  • 多線程 在iOS開發(fā)中為提高程序的運(yùn)行效率會(huì)將比較耗時(shí)的操作放在子線程中執(zhí)行政鼠,iOS系統(tǒng)進(jìn)程默認(rèn)啟動(dòng)一個(gè)主線程,用...
    郭豪豪閱讀 2,601評(píng)論 0 4
  • 2018年4月23日 星期一 陰轉(zhuǎn)雨 燦陽媽感恩日記 讀經(jīng)人員:燦陽媽公般,燦燦器躏、陽陽 蟹略、三寶 一登失、讀經(jīng)內(nèi)容 1.燦陽...
    三寶媽肖雪強(qiáng)閱讀 277評(píng)論 0 0
  • 兔子也戀荷塘揽浙, 裝作人模人樣意敛; 豎起兩只耳朵, 夢(mèng)幻勝利時(shí)光草姻。
    凱陵閱讀 233評(píng)論 0 0
  • 曾經(jīng)看到別人說過账月,如果你想了解一個(gè)城市澳迫,乘公交是最好的方式,穿行于大街小巷或是林立高樓橄登,城市的風(fēng)景如畫卷一般鋪展在...
    嚯嚯哈哈嘿閱讀 327評(píng)論 0 0