多線程(一)

面試題

1.你理解的多線程?
2.ios的多線程方案有哪幾種恕洲?你更傾向于哪一種?
3.你在項目中用過GCD?
4.GCD的隊列類型
5.說一下OperationQueue和GCD的區(qū)別盐碱、以及各自的優(yōu)勢
6.線程安全的處理手段有哪些楼誓?
7.OC你了解的鎖有哪些玉锌?
    - 自旋和互斥對比?
    - 使用以上鎖需要注意哪些疟羹?
  - 用C/OC/C++主守,任選其一,實現(xiàn)自旋或互斥榄融?

下面我們來看看幾個例子

代碼詳見 gitHub_Demo

例1

#import "ViewController_1.h"
@interface ViewController_1 ()
@end

@implementation ViewController_1
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //這句代碼的本質是往Runloop中添加定時器  如果在主線程参淫,runloop自動開啟好了的
    [self performSelector:@selector(test1) withObject:nil afterDelay:.0];//afterDelay-->異步執(zhí)行的 主隊列
    //主隊列異步執(zhí)行時,會先執(zhí)行完主線程上的代碼愧杯,然后在主線程上順序執(zhí)行任務涎才,不會有新的線程產生,所有任務都是在主線程上完成的
    
    NSLog(@"%@",[NSThread currentThread]);
    
    sleep(1);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"asyncThread--%@",[NSThread currentThread]);
        NSLog(@"1");
        
        //如果是子線程需要自己手動去啟動runloop
        [self performSelector:@selector(test) withObject:nil afterDelay:.0];
        
        //手動去啟動runloop
//        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        
        NSLog(@"3");
    });
    NSLog(@"4");
}

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

-(void)test1{
    NSLog(@"test1Thread---%@",[NSThread currentThread]);
    NSLog(@"test1");
}
@end

打用裥А:
沒有手動去啟動runloop
Multithreading[17114:917201] <NSThread: 0x600000501400>{number = 1, name = main}
Multithreading[17114:917201] 4
Multithreading[17114:917201] test1Thread---<NSThread: 0x600000501400>{number = 1, name = main}
Multithreading[17114:917201] test1
Multithreading[17114:917255] asyncThread--<NSThread: 0x6000005825c0>{number = 3, name = (null)}
Multithreading[17114:917255] 1
Multithreading[17114:917255] 3

=========================================
手動去啟動runloop
Multithreading[17130:918365] <NSThread: 0x600000ef1400>{number = 1, name = main}
Multithreading[17130:918365] 4
Multithreading[17130:918365] test1Thread---<NSThread: 0x600000ef1400>{number = 1, name = main}
Multithreading[17130:918365] test1
Multithreading[17130:918422] asyncThread--<NSThread: 0x600000e712c0>{number = 3, name = (null)}
Multithreading[17130:918422] 1
Multithreading[17130:918422] 2
Multithreading[17130:918422] 3

例2

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

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1"); //一完成任務之后憔维,子線程就退出了
    }];
    [thread start];
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
    NSLog(@"===End====");
}

運行結果:NSLog(@"1") 之后 崩潰了
Multithreading_01.png
- (void)test{
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");        
    //一完成任務之后,子線程就退出了
    }];
    
    [thread start];
    
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:NO];
    
    sleep(2);
    NSLog(@"===End====");
}
打游沸稀:
Multithreading[19178:1044135] 1
Multithreading[19178:1043871] ===End====
Multithreading_02.png
修改崩潰:
- (void)test{
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }];
    
    [thread start];
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
    
    sleep(2);
    NSLog(@"===End====");
}
打右蛋恰:
Multithreading[19214:1046668] 1
Multithreading[19214:1046668] 2
Multithreading[19214:1046548] ===End====

【開啟了runloop后,延長了子線程的生命】
【如果沒有舒萎,則會執(zhí)行完任務子線程就退出了】

iOS中的常見多線程方案

Multithreading_03.png

GCD的常用函數(shù)

Multithreading_04.png

GCD的隊列

Multithreading_05.png
//異步開啟子線程程储,執(zhí)行任務
-(void)test1{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
    dispatch_async(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
        // <NSThread: 0x6000033da280>{number = 3, name = (null)}
    });
}


//同步,在當前線程執(zhí)行任務
-(void)test2{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
    dispatch_sync(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
        // <NSThread: 0x600002442c80>{number = 1, name = main}
    });
}


//同步臂寝,在當前線程執(zhí)行任務(并發(fā)無效 )
-(void)test3{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
    dispatch_sync(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
        }
    });
    
    /*
    執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
    執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
     */
}


//異步章鲤,開啟新線程執(zhí)行任務(并發(fā))
-(void)test4{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
        }
    });
    
    /*
     執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
     執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
     執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
     執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
     執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
     執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
     */
}


//串行隊列異步執(zhí)行任務 (按順序執(zhí)行)
-(void)test5{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊列
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
        }
    });
    /*
     執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
     */
}


//在當前線程(此時是主線程),串行執(zhí)行任務
-(void)test6{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊列
    dispatch_sync(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
        }
    });
    
    /*
     執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
     */
}


//主隊列里面異步執(zhí)行(此時沒有開啟新的線程)
-(void)test7{
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for(int i=0;i<5;i++){
            NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
        }
    });
    /*
     執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
     執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
     */
}

容易混淆的術語

Multithreading_06.png
dispatch_sync和dispatch_async用來控制是否要開啟新的線程
 
隊列的類型咆贬,決定了任務的執(zhí)行方式(并發(fā)败徊、串行)
 1.并發(fā)隊列
 2.串行隊列
 3.主隊列(也是一個串行隊列)

注意:異步的它不一定 要開啟新的線程(只是具備開啟新的線程的能力)
主隊列里面異步執(zhí)行任務

只要是sync(同步),或者是在主隊列里掏缎,他就是在當前線程里面執(zhí)行任務皱蹦,那它一定是串行執(zhí)行任務

沒有開啟新的線程,那它肯定是串行 執(zhí)行任務的

各種隊列的執(zhí)行效果

Multithreading_07.png

總結:

Multithreading_08.png

友情鏈接:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末眷蜈,一起剝皮案震驚了整個濱河市沪哺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酌儒,老刑警劉巖辜妓,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡籍滴,警方通過查閱死者的電腦和手機酪夷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來异逐,“玉大人捶索,你說我怎么就攤上這事』艺埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵辅甥,是天一觀的道長酝润。 經常有香客問我,道長璃弄,這世上最難降的妖魔是什么要销? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮夏块,結果婚禮上疏咐,老公的妹妹穿的比我還像新娘。我一直安慰自己脐供,他們只是感情好浑塞,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著政己,像睡著了一般酌壕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歇由,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天卵牍,我揣著相機與錄音,去河邊找鬼沦泌。 笑死娶牌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的宿崭。 我是一名探鬼主播愿阐,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼他宛!你這毒婦竟也來了船侧?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤厅各,失蹤者是張志新(化名)和其女友劉穎镜撩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡袁梗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年宜鸯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遮怜。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡淋袖,死狀恐怖,靈堂內的尸體忽然破棺而出锯梁,到底是詐尸還是另有隱情即碗,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布陌凳,位于F島的核電站剥懒,受9級特大地震影響,放射性物質發(fā)生泄漏合敦。R本人自食惡果不足惜初橘,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望充岛。 院中可真熱鬧保檐,春花似錦、人聲如沸崔梗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炒俱。三九已至盐肃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間权悟,已是汗流浹背砸王。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留峦阁,地道東北人谦铃。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓榔昔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撒会。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內容

  • 首先了解單線程:一诵肛、單線程的應用,整個應用中只有一個順序執(zhí)行流,當執(zhí)行流在執(zhí)行某個耗時的操作,或者不能立即完成的任...
    藍白七七閱讀 575評論 1 8
  • iOS開發(fā)中經常要使用到多線程,在面試的時候也是經常問到,比較常見的面試題有下面這些: iOS的多線程方案有哪幾種...
    雪山飛狐_91ae閱讀 857評論 0 2
  • 由于前段時間蓄诽,堂弟的詢問,再加上自己也想重新整理一下知識結構媒吗,就梳理一下知識。一系列的文章闸英,可能會很多锯岖,也可能會很...
    攝影師諾風閱讀 675評論 5 15
  • 多線程涉及到的概念: 進程嚎莉,線程,主線程沛豌,任務,隊列赃额,死鎖加派,串行,并行跳芳,同步芍锦,異步,GCD飞盆,NSOperation...
    BadGirl_TONG閱讀 209評論 0 1
  • 白天黑夜抽絲剝繭著身體娄琉,迎著朝陽夕霞舞動著白白骷髏,褪去偽裝剩下的只是皮和肉 吓歇∧跛——迷途人
    清修_d5a0閱讀 199評論 0 0