多線程(一)

面試題

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

下面我們來看看幾個(gè)例子

代碼詳見 gitHub_Demo

例1

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

@implementation ViewController_1
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //這句代碼的本質(zhì)是往Runloop中添加定時(shí)器  如果在主線程,runloop自動(dòng)開啟好了的
    [self performSelector:@selector(test1) withObject:nil afterDelay:.0];//afterDelay-->異步執(zhí)行的 主隊(duì)列
    //主隊(duì)列異步執(zhí)行時(shí),會(huì)先執(zhí)行完主線程上的代碼,然后在主線程上順序執(zhí)行任務(wù),不會(huì)有新的線程產(chǎn)生,所有任務(wù)都是在主線程上完成的
    
    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");
        
        //如果是子線程需要自己手動(dòng)去啟動(dòng)runloop
        [self performSelector:@selector(test) withObject:nil afterDelay:.0];
        
        //手動(dòng)去啟動(dòng)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

打?。?沒有手動(dòng)去啟動(dòng)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

=========================================
手動(dòng)去啟動(dòng)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"); //一完成任務(wù)之后,子線程就退出了
    }];
    [thread start];
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
    NSLog(@"===End====");
}

運(yùn)行結(jié)果:NSLog(@"1") 之后 崩潰了
Multithreading_01.png
- (void)test{
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");        
    //一完成任務(wù)之后,子線程就退出了
    }];
    
    [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后,延長了子線程的生命】
【如果沒有,則會(huì)執(zhí)行完任務(wù)子線程就退出了】

iOS中的常見多線程方案

Multithreading_03.png

GCD的常用函數(shù)

Multithreading_04.png

GCD的隊(duì)列

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


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


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


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


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


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


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

容易混淆的術(shù)語

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

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

只要是sync(同步),或者是在主隊(duì)列里,他就是在當(dāng)前線程里面執(zhí)行任務(wù),那它一定是串行執(zhí)行任務(wù)

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

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

Multithreading_07.png

總結(jié):

Multithreading_08.png

友情鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 首先了解單線程:一、單線程的應(yīng)用,整個(gè)應(yīng)用中只有一個(gè)順序執(zhí)行流,當(dāng)執(zhí)行流在執(zhí)行某個(gè)耗時(shí)的操作,或者不能立即完成的任...
    甘哲157閱讀 698評(píng)論 1 8
  • iOS開發(fā)中經(jīng)常要使用到多線程,在面試的時(shí)候也是經(jīng)常問到,比較常見的面試題有下面這些: iOS的多線程方案有哪幾種...
    雪山飛狐_91ae閱讀 914評(píng)論 0 2
  • 由于前段時(shí)間,堂弟的詢問,再加上自己也想重新整理一下知識(shí)結(jié)構(gòu),就梳理一下知識(shí)。一系列的文章,可能會(huì)很多,也可能會(huì)很...
    攝影師諾風(fēng)閱讀 717評(píng)論 5 15
  • 多線程涉及到的概念: 進(jìn)程,線程,主線程,任務(wù),隊(duì)列,死鎖,串行,并行,同步,異步,GCD,NSOperation...
    BadGirl_TONG閱讀 235評(píng)論 0 1
  • 白天黑夜抽絲剝繭著身體,迎著朝陽夕霞舞動(dòng)著白白骷髏,褪去偽裝剩下的只是皮和肉 。——迷途人
    清修_d5a0閱讀 254評(píng)論 0 0

友情鏈接更多精彩內(nèi)容