美文网首页iOS知识收集iOS DevGCD
iOS-GCD之初,disPatch队列和线程的关系

iOS-GCD之初,disPatch队列和线程的关系

作者: SOI | 来源:发表于2016-02-05 23:11 被阅读3629次

    关于GCD的最最基本的知识,往往很多初学者都被忽略。理解上造成了偏差,而不注重去实践, 所有我们需要认真的总结一下。

    dispatch_asyn和dispatch_sync添加任务到dispatch队列时,是否创建线程呢,那么创建线程是创建一个呢还是多个呢,如果你自己能直接分的清楚就不必看我下文的实践代码了, 下文的代码做了详细的说明, 不仅仅是代码,也包含了总结, 如果你想实践的话, 也可以跟着实践一遍哦,这样最好哦

    以下主要总结了队列的类型队列的堵塞

    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        
        //********
        [self blockIntroduced];
        //********通过以上测试我们得出如下几个结论
        
        /*
         1.dispatch_sync添加任务到队列,不会创建新的线程都是在当前线程中处理的。无论添加到串行队列里或者并行队列里,都是串行效果,因为这个方法是等任务执行完成以后才会返回。
         2.dispatch_async添加任务到
           2-1:mainQueue不创建线程,在主线程中串行执行
           2-2:globalQueue 和 并行队列:根据任务系统决定开辟线程个数
           2-3:串行对列:创建一个线程:串行执行。
         
        */
        
        
        [self blockedMainThread0];
        [self blockedMainThread1];
        [self blockedMainThread2];
        [self blockedMainThread3];
    //    [self blockedMainThread];
        
    }
    
    -(void)blockIntroduced
    {
        //队列一般就是系统的主队列和全局队列还有自己手动创建的串行队列和并行队列
        dispatch_queue_t chuanxingduilie = dispatch_queue_create("chuanxingduilie", DISPATCH_QUEUE_SERIAL);
        dispatch_queue_t bingxingduilie = dispatch_queue_create("bingxingduilie", DISPATCH_QUEUE_CONCURRENT);
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
        
        //方法有两个  dispatch_sync 和 dispatch_async  dispatch_async方法是立刻返回的,也就是说把block内容加到相应队列里后会立马返回,而dispatch_sync要等到加到队列里执行完之后才会返回。
        //这时候总共有2*4 = 8种组合,接下来我们来说一下这八种组合
        
        
        //一:
        for(int i=0;i<3;i++){
            dispatch_sync(chuanxingduilie, ^{
                NSLog(@"dispatch_sync-chuanxingduilie-%d\n mainThread:%@",i,[NSThread currentThread]);
            });
        }
        /*
         2016-02-05 21:07:12.622 GcdTest[7229:164997] dispatch_sync-chuanxingduilie-0
         mainThread:<NSThread: 0x7fad93407dd0>{number = 1, name = main}
         2016-02-05 21:07:12.623 GcdTest[7229:164997] dispatch_sync-chuanxingduilie-1
         mainThread:<NSThread: 0x7fad93407dd0>{number = 1, name = main}
         2016-02-05 21:07:12.623 GcdTest[7229:164997] dispatch_sync-chuanxingduilie-2
         mainThread:<NSThread: 0x7fad93407dd0>{number = 1, name = main}
    
         */
        //第一种方式可见,串行队列是在主线程里完成的,因为是串行队列,所以打印%d是有顺序的。
        
        //二:
        for(int i=0;i<3;i++){
            dispatch_sync(bingxingduilie, ^{
                
                NSLog(@"dispatch_sync-bingxingduilie-%d\n mainThread:%@",i,[NSThread currentThread]);
        
            });
        }
        /*
         2016-02-05 21:09:26.422 GcdTest[7241:165846] dispatch_sync-bingxingduilie-0
         mainThread:<NSThread: 0x7face9d01d20>{number = 1, name = main}
         2016-02-05 21:09:26.422 GcdTest[7241:165846] dispatch_sync-bingxingduilie-1
         mainThread:<NSThread: 0x7face9d01d20>{number = 1, name = main}
         2016-02-05 21:09:26.422 GcdTest[7241:165846] dispatch_sync-bingxingduilie-2
         mainThread:<NSThread: 0x7face9d01d20>{number = 1, name = main}
    
        */
        //第二种方式可以发现同样还是在主线程里执行并行队列,(虽然是并行队列,但这时候依然在同一个线程里执行)
        
        //三:
        /*
        for(int i=0;i<3;i++){
            NSLog(@"dispatch_sync-mainQueue");
            dispatch_sync(mainQueue, ^{
                
                NSLog(@"dispatch_sync-mainQueue-%d\n mainThread:%@",i,[NSThread currentThread]);
                
            });
        }
        //打印结果:dispatch_sync-mainQueue,发现主线程被堵塞。原因在堵塞中分析。此种方式暂时先屏蔽掉
        */
        
        //四:
        for(int i=0;i<3;i++){
            dispatch_sync(globalQueue, ^{
                
                NSLog(@"dispatch_sync-globalQueue-%d\n mainThread:%@",i,[NSThread currentThread]);
                
            });
        }
        /*
         2016-02-05 21:22:41.107 GcdTest[7338:172870] dispatch_sync-globalQueue-0
         mainThread:<NSThread: 0x7feadad050b0>{number = 1, name = main}
         2016-02-05 21:22:41.107 GcdTest[7338:172870] dispatch_sync-globalQueue-1
         mainThread:<NSThread: 0x7feadad050b0>{number = 1, name = main}
         2016-02-05 21:22:41.107 GcdTest[7338:172870] dispatch_sync-globalQueue-2
         mainThread:<NSThread: 0x7feadad050b0>{number = 1, name = main}
         */
        //打印结果可以看出依然是主线程。
        
        //五:
        for (int i=0; i<3; i++) {
            dispatch_async(chuanxingduilie, ^{
                if (i==1) {
                    sleep(2);
                }
                NSLog(@"dispatch_async-chuanxingduilie-%d\n Thread:%@",i,[NSThread currentThread]);
            });
        }
        /*
         2016-02-05 22:32:14.957 GcdTest[7499:191789] dispatch_async-chuanxingduilie-0
         Thread:<NSThread: 0x7fd7eaf10c70>{number = 3, name = (null)}
         2016-02-05 22:32:16.962 GcdTest[7499:191789] dispatch_async-chuanxingduilie-1
         Thread:<NSThread: 0x7fd7eaf10c70>{number = 3, name = (null)}
         2016-02-05 22:32:16.963 GcdTest[7499:191789] dispatch_async-chuanxingduilie-2
         Thread:<NSThread: 0x7fd7eaf10c70>{number = 3, name = (null)}
         */
        //可以看出创建了一个线程, 在串行队列里串行执行的
        
        
        //六:
        for (int i=0; i<3; i++) {
            dispatch_async(bingxingduilie, ^{
                if (i==1) {
                    sleep(3);
                }
                NSLog(@"dispatch_async-bingxingduilie-%d\n Thread:%@",i,[NSThread currentThread]);
            });
        }
        /*
         2016-02-05 22:10:07.083 GcdTest[7425:184003] dispatch_async-bingxingduilie-2
         Thread:<NSThread: 0x7fcda24bcd00>{number = 4, name = (null)}
         2016-02-05 22:10:07.083 GcdTest[7425:183982] dispatch_async-bingxingduilie-0
         Thread:<NSThread: 0x7fcda2502310>{number = 3, name = (null)}
         2016-02-05 22:10:10.083 GcdTest[7425:184002] dispatch_async-bingxingduilie-1
         Thread:<NSThread: 0x7fcda2436180>{number = 5, name = (null)}
         */
        //分析可以看出创建了多个线程,任务执行顺序不一定(时间差不多的话)
        
        
        //七:
        for (int i=0; i<3; i++) {
            dispatch_async(mainQueue, ^{
                if (i==1) {
                    sleep(3);
                }
                NSLog(@"dispatch_async-mainQueue-%d\n Thread:%@",i,[NSThread currentThread]);
            });
        }
        /*
         Thread:<NSThread: 0x7fbb28704510>{number = 5, name = (null)}
         2016-02-05 22:15:03.709 GcdTest[7460:186485] dispatch_async-mainQueue-0
         Thread:<NSThread: 0x7fbb28703fb0>{number = 1, name = main}
         2016-02-05 22:15:06.710 GcdTest[7460:186485] dispatch_async-mainQueue-1
         Thread:<NSThread: 0x7fbb28703fb0>{number = 1, name = main}
         2016-02-05 22:15:06.710 GcdTest[7460:186485] dispatch_async-mainQueue-2
         Thread:<NSThread: 0x7fbb28703fb0>{number = 1, name = main}
         */
        
        //可以看出这种情况还是在当前线程环境中执行,并不创建线程,因为是在主队列里,顺序执行
        
        //八:
        for (int i=0; i<3; i++) {
            dispatch_async(globalQueue, ^{
            
                NSLog(@"dispatch_async-globalQueue-%d\n Thread:%@",i,[NSThread currentThread]);
            });
        }
        /*
         2016-02-05 22:17:58.306 GcdTest[7482:188067] dispatch_async-globalQueue-1
         Thread:<NSThread: 0x7fa281e24580>{number = 4, name = (null)}
         2016-02-05 22:17:58.306 GcdTest[7482:188099] dispatch_async-globalQueue-2
         Thread:<NSThread: 0x7fa281e321c0>{number = 5, name = (null)}
         2016-02-05 22:17:58.307 GcdTest[7482:188069] dispatch_async-globalQueue-0
         Thread:<NSThread: 0x7fa281e262b0>{number = 3, name = (null)}
         */
       //可以看出创建了多个线程,执行顺序并不一定
    
    }
    
    -(void)blockedMainThread
    {
      //打印结果是1  分析:mainQueue里存在任务1,同步线程任务,这两个任务,当执行dispatch_sync时,把打印任务2加入主队列,想要打印2必须等之前所有的任务都执行完成,这时候因为主队列里有同步线程任务,这时候相当于自己在等自己执行完成,进入死循环。
        NSLog(@"1"); // 任务1
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2"); // 任务2
        });
        NSLog(@"3"); // 任务3
    
    }
    
    -(void)blockedMainThread0
    {
        //打印结果123  分析:mainQueue里存在任务1,同步线程任务,当执行dispatch_sync时,拿到全局队列,
        NSLog(@"1"); // 任务1
        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSLog(@"2"); // 任务2
        });
        NSLog(@"3"); // 任务3
    }
    
    -(void)blockedMainThread1
    {
        /*
        //执行结果:
        2016-02-05 22:42:30.661 GcdTest[7511:194820] 1
        2016-02-05 22:42:30.662 GcdTest[7511:194820] 5
        2016-02-05 22:42:30.662 GcdTest[7511:194929] 2 <NSThread: 0x7f9ca8709990>{number = 3, name = (null)}
         */
        dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
        NSLog(@"1"); // 任务1
        dispatch_async(queue, ^{
            NSLog(@"2 %@",[NSThread currentThread]); // 任务2
            
            dispatch_sync(queue, ^{
                NSLog(@"3"); // 任务3
            });
            NSLog(@"4"); // 任务4
        });
        NSLog(@"5"); // 任务5
    }
    
    -(void)blockedMainThread2
    {
        //1,5,2,3,4 可以看出在全局队列里拿到住队列同步执行是没有问题的。
        NSLog(@"****************");
        NSLog(@"1"); // 任务1
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"2"); // 任务2
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"3 %@",[NSThread currentThread]); // 任务3
                //2016-02-05 22:51:00.044 GcdTest[7548:198417] 3 <NSThread: 0x7feb3b701be0>{number = 1, name = main}
            });
            NSLog(@"4"); // 任务4
        });
        NSLog(@"5"); // 任务5
    
    }
    
    -(void)blockedMainThread3
    {
        //执行结果:11,44
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"11"); // 任务1
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"22"); // 任务2
            });
            NSLog(@"33"); // 任务3
        });
        NSLog(@"44"); // 任务4
        while (1) {
        }
        NSLog(@"55"); // 任务5
    }
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    

    文章未完待续:待续内容为dispatch里的大部分常用的方法,等我有时间了一定会更新上去, 如果大家喜欢文章, 就关注哦~
    有什么不明白的,可以直接评论回复,交流。

    1.dispath_once

    dispatch_once的作用就是只执行一次,我们在写单例的时候可以用到

    + (BWStatusBarOverlay *)shared {
        static dispatch_once_t pred = 0;
        __strong static id _sharedObject = nil;
        dispatch_once(&pred, ^{
            _sharedObject = [[self alloc] init];
        });
        return _sharedObject;
    }
    

    2.dispatch_after

    //延迟0.5s以后执行
       dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*0.5);
        dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"doSomething");
        });
    

    3.dispatch_group

    
        dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, globalQueue, ^{
             sleep(1);
            NSLog(@"1");
        });
        dispatch_group_async(group, globalQueue, ^{
            sleep(2);
            NSLog(@"2");
        });
        dispatch_group_async(group, globalQueue, ^{
            sleep(3);
            NSLog(@"3");
        });
        dispatch_group_notify(group, globalQueue, ^{
            NSLog(@"Over!");
        });
    

    4.dispatch_barrier_async

    
        dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-1");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-2");
        });
        dispatch_barrier_async(concurrentQueue, ^(){
            NSLog(@"dispatch-barrier-1+2");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-3");
        });
        dispatch_barrier_async(concurrentQueue, ^{
            NSLog(@"dispatch-barrier-1+2+3");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-4");
        });
    

    最后不多说,需要看看苹果官方文档这里截图看下关于GCD的东西

    gcd-1.png gcd-2.png gcd-3.png

    看官方的东西其实不会的东西太多太多,任重而道远, 明天就回家过年喽, 祝愿每一个人新的一年都能对自己的目标更近一步。

    相关文章

      网友评论

      • swiftly_zhou:+ (BWStatusBarOverlay *)shared {
        static dispatch_once_t pred = 0;
        __strong static id _sharedObject = nil;
        dispatch_once(&pred, ^{
        _sharedObject = [[self alloc] init];
        });
        return _sharedObject;
        }

        没必要用__strong 这个修饰符,被static 修饰的 _sharedObject 变量被放到了 静态存储区,只有在app程序退出时,才会被销毁。
      • sonialiu:如果面试官问:队列和线程的关系是什么?请问从哪些方面回答呀?
        迷迭象:队列是一个存放任务的容器,而线程是执行这些任务的东西
      • 大墙66370:blockedMainThread01234这几个方法打印结果不解释一下吗?
        大墙66370:@孙清泉 谢谢
        PotterSun:@大墙66370 你看懂了下面一片文章总结的死锁规则,再看这个就好理解了
        http://www.jianshu.com/p/b355e1633f05
        大墙66370:@大墙66370 时隔半年,再来一遍:smile:
      • 大墙66370:-(void)blockedMainThread3这个我得执行结果是
        44 11 。停了一会运行就是11 44了。这个现象正常吗?
        大墙66370:@SOI 谢谢回复
        SOI:@大墙66370 正常,dispatch_asyn会立刻返回,执行下面的代码,和把block塞到队列里不一定哪个先执行,具有不确定性
      • 芮星晨:学习了,可惜没有swift语言的
        SOI:@芮星晨 swift语言的有时间了更新下

      本文标题:iOS-GCD之初,disPatch队列和线程的关系

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