美文网首页
多线程(一)

多线程(一)

作者: dandelionYD | 来源:发表于2019-04-12 09:26 被阅读0次

    面试题

    1.你理解的多线程?
    2.ios的多线程方案有哪几种?你更倾向于哪一种?
    3.你在项目中用过GCD?
    4.GCD的队列类型
    5.说一下OperationQueue和GCD的区别、以及各自的优势
    6.线程安全的处理手段有哪些?
    7.OC你了解的锁有哪些?
        - 自旋和互斥对比?
        - 使用以上锁需要注意哪些?
      - 用C/OC/C++,任选其一,实现自旋或互斥?
    

    下面我们来看看几个例子

    代码详见 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-->异步执行的 主队列
        //主队列异步执行时,会先执行完主线程上的代码,然后在主线程上顺序执行任务,不会有新的线程产生,所有任务都是在主线程上完成的
        
        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后,延长了子线程的生命】
    【如果没有,则会执行完任务子线程就退出了】
    

    iOS中的常见多线程方案

    Multithreading_03.png

    GCD的常用函数

    Multithreading_04.png

    GCD的队列

    Multithreading_05.png
    //异步开启子线程,执行任务
    -(void)test1{
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并发队列
        dispatch_async(queue, ^{
            NSLog(@"%@",[NSThread currentThread]);
            // <NSThread: 0x6000033da280>{number = 3, name = (null)}
        });
    }
    
    
    //同步,在当前线程执行任务
    -(void)test2{
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并发队列
        dispatch_sync(queue, ^{
            NSLog(@"%@",[NSThread currentThread]);
            // <NSThread: 0x600002442c80>{number = 1, name = main}
        });
    }
    
    
    //同步,在当前线程执行任务(并发无效 )
    -(void)test3{
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并发队列
        dispatch_sync(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务1:%@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务2:%@",[NSThread currentThread]);
            }
        });
        
        /*
        执行任务1:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务1:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务1:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务1:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务1:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务2:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务2:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务2:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务2:<NSThread: 0x600002b66980>{number = 1, name = main}
        执行任务2:<NSThread: 0x600002b66980>{number = 1, name = main}
         */
    }
    
    
    //异步,开启新线程执行任务(并发)
    -(void)test4{
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并发队列
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务1:%@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务2:%@",[NSThread currentThread]);
            }
        });
        
        /*
         执行任务1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
         执行任务1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
         执行任务2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
         执行任务1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
         执行任务1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
         执行任务1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
         */
    }
    
    
    //串行队列异步执行任务 (按顺序执行)
    -(void)test5{
        dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行队列
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务1:%@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务2:%@",[NSThread currentThread]);
            }
        });
        /*
         执行任务1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         执行任务2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
         */
    }
    
    
    //在当前线程(此时是主线程),串行执行任务
    -(void)test6{
        dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行队列
        dispatch_sync(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务1:%@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务2:%@",[NSThread currentThread]);
            }
        });
        
        /*
         执行任务1:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600000c69400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600000c69400>{number = 1, name = main}
         */
    }
    
    
    //主队列里面异步执行(此时没有开启新的线程)
    -(void)test7{
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务1:%@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for(int i=0;i<5;i++){
                NSLog(@"执行任务2:%@",[NSThread currentThread]);
            }
        });
        /*
         执行任务1:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务1:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600003d7d400>{number = 1, name = main}
         执行任务2:<NSThread: 0x600003d7d400>{number = 1, name = main}
         */
    }
    

    容易混淆的术语

    Multithreading_06.png
    dispatch_sync和dispatch_async用来控制是否要开启新的线程
     
    队列的类型,决定了任务的执行方式(并发、串行)
     1.并发队列
     2.串行队列
     3.主队列(也是一个串行队列)
    
    注意:异步的它不一定 要开启新的线程(只是具备开启新的线程的能力)
    主队列里面异步执行任务
    
    只要是sync(同步),或者是在主队列里,他就是在当前线程里面执行任务,那它一定是串行执行任务
    
    没有开启新的线程,那它肯定是串行 执行任务的
    

    各种队列的执行效果

    Multithreading_07.png

    总结:

    Multithreading_08.png

    友情链接:

    相关文章

      网友评论

          本文标题:多线程(一)

          本文链接:https://www.haomeiwen.com/subject/gxdqwqtx.html