美文网首页iOS进阶之路
iOS多线程(一):GCD的基本使用

iOS多线程(一):GCD的基本使用

作者: 康小曹 | 来源:发表于2018-11-22 14:49 被阅读6次

    一、什么是GCD

    GCD:grand central dispatch 牛逼的中枢调度器
    特点:
    1.纯C语言API
    2.apple官方出品
    3.自动管理生命周期(ARC中)
    4.只需要告诉GCD需要执行的任务,操作简单

    二、GCD的使用

    1、队列的使用和创建

    队列:存放需要执行的任务的容器。而执行这些任务的是线程。队列不一定创建线程,如果不创建线程,则当前线程来执行这些队列中的任务。

    创建串行队列

        /**
         创建队列
         
         @param "concurrentQueue" 队列名称
         @param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列
         @return 队列
         */
        dispatch_queue_t t3 = dispatch_queue_create("serialQueue", NULL);
    

    获取全局并发队列

        /**
         直接获取全局并发队列
    
         @param QOS_CLASS_DEFAULT 优先级别,有两种方式表示,详见API官方注释
         @param 0 预留参数,传0
         @return 全局并发队列
         */
        dispatch_queue_t t1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

    创建并发队列

        /**
         创建队列
    
         @param "concurrentQueue" 队列名称
         @param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列
         @return 队列
         */
        dispatch_queue_t t2 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
    2、执行任务

    任务的执行步骤:创建任务和队列后,将任务添加到队列中,最后根据asyn和syn来判断是否需要创建线程以及在哪个线程执行

    异步执行队列中的任务

    dispatch_async(queue, ^{
            NSLog(@"1---%@",[NSThread currentThread]);
        });
    

    同步执行队列中的任务

    dispatch_sync(queue, ^{
            NSLog(@"1---%@",[NSThread currentThread]);
        });
    

    三、四种情况

    1、串行队列同步执行
    - (void)syncTaskWithSerialQueue {
        NSLog(@"syncTaskWithSerialQueue---start");
        
        dispatch_queue_t queue = dispatch_queue_create("serialQueue", NULL);
        
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"1---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"2---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"3---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"4---%@",[NSThread currentThread]);
        });
        
        NSLog(@"syncTaskWithSerialQueue---end");
    }
    

    结果:

    2018-11-21 15:25:03.037 XKQuote[51245:4129046] syncTaskWithSerialQueue---start
    2018-11-21 15:25:04.037 XKQuote[51245:4129046] 1---<NSThread: 0x7f974a502b80>{number = 1, name = main}
    2018-11-21 15:25:05.038 XKQuote[51245:4129046] 2---<NSThread: 0x7f974a502b80>{number = 1, name = main}
    2018-11-21 15:25:06.040 XKQuote[51245:4129046] 3---<NSThread: 0x7f974a502b80>{number = 1, name = main}
    2018-11-21 15:25:07.040 XKQuote[51245:4129046] 4---<NSThread: 0x7f974a502b80>{number = 1, name = main}
    2018-11-21 15:25:07.041 XKQuote[51245:4129046] syncTaskWithSerialQueue---end
    

    总结:
    1.串行队列中同步执行任务不会创建线程,在当前线程中执行
    2.顺序执行
    3.阻塞当前线程
    4.同步执行会等待当前队列中的任务执行完毕,才会接着执行

    2、串行队列异步执行
    - (void)asyncTaskWithSerialQueue {
        NSLog(@"asyncTaskWithSerialQueue---start");
        dispatch_queue_t queue = dispatch_queue_create("serial2", NULL);
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"asyncTaskWithSerialQueue:1---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"asyncTaskWithSerialQueue:2---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"asyncTaskWithSerialQueue:3---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"asyncTaskWithSerialQueue:4---%@",[NSThread currentThread]);
        });
        
        NSLog(@"asyncTaskWithSerialQueue---end");
    }
    

    结果

    2018-11-22 15:01:42.505 XKQuote[14265:4858578] asyncTaskWithSerialQueue---start
    2018-11-22 15:01:42.506 XKQuote[14265:4858578] asyncTaskWithSerialQueue---end
    2018-11-22 15:01:43.510 XKQuote[14265:4858727] asyncTaskWithSerialQueue:1---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
    2018-11-22 15:01:44.514 XKQuote[14265:4858727] asyncTaskWithSerialQueue:2---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
    2018-11-22 15:01:45.518 XKQuote[14265:4858727] asyncTaskWithSerialQueue:3---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
    2018-11-22 15:01:46.523 XKQuote[14265:4858727] asyncTaskWithSerialQueue:4---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
    

    总结
    1.开启了线程,但是只开启了一个;
    2.所有任务都在开启的那个线程中按顺序执行

    3、并行队列同步执行
    - (void)syncTaskWithConcurrentQueue {
        NSLog(@"syncTaskWithConcurrentQueue---begin");
        dispatch_queue_t queue = dispatch_queue_create("concurrent1", DISPATCH_QUEUE_CONCURRENT);
    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_sync(queue, ^{
            NSLog(@"syncTaskWithConcurrentQueue:1---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"syncTaskWithConcurrentQueue:2---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"syncTaskWithConcurrentQueue:3---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"syncTaskWithConcurrentQueue:4---%@",[NSThread currentThread]);
        });
        NSLog(@"syncTaskWithConcurrentQueue---end");
    }
    

    结果

    2018-11-22 15:05:25.698 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---begin
    2018-11-22 15:05:26.700 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:1---<NSThread: 0x7fa141d05210>{number = 1, name = main}
    2018-11-22 15:05:27.701 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:2---<NSThread: 0x7fa141d05210>{number = 1, name = main}
    2018-11-22 15:05:28.702 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:3---<NSThread: 0x7fa141d05210>{number = 1, name = main}
    2018-11-22 15:05:29.703 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:4---<NSThread: 0x7fa141d05210>{number = 1, name = main}
    2018-11-22 15:05:29.704 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---end
    

    总结
    1.并行队列中同步执行不会创建新的线程;
    2.在当前线程中顺序执行,会阻塞线程;
    3.并发的前提是多线程
    4.同步执行会等待当前队列中的任务执行完毕,才会接着执行

    4、并行队列异步执行
    - (void)asyncTaskWithConcurrentQueue {
        NSLog(@"asyncTaskWithSerialQueue---start");
        
        dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"1---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"2---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"3---%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"4---%@",[NSThread currentThread]);
        });
        
        NSLog(@"syncTaskWithSerialQueue---end");
    }
    
    2018-11-21 16:11:31.372 XKQuote[51304:4131596] asyncTaskWithSerialQueue---start
    2018-11-21 16:11:31.372 XKQuote[51304:4131596] syncTaskWithSerialQueue---end
    2018-11-21 16:11:32.372 XKQuote[51304:4183129] 1---<NSThread: 0x7fdff3504af0>{number = 6, name = (null)}
    2018-11-21 16:11:32.372 XKQuote[51304:4187339] 2---<NSThread: 0x7fdff372f090>{number = 7, name = (null)}
    2018-11-21 16:11:32.373 XKQuote[51304:4187341] 4---<NSThread: 0x7fdff342dd80>{number = 8, name = (null)}
    2018-11-21 16:11:32.373 XKQuote[51304:4187340] 3---<NSThread: 0x7fdff3413a40>{number = 9, name = (null)}
    

    总结
    1.并行队列异步执行创建了新的队列(具体创建几个队列由GCD自己控住)
    2.不阻塞当前线程;
    3.不是顺序执行(对比:gropu,优先级)

    大总结
    sync+serial = sync + concurrent
    async+serial:新开一个线程顺序执行
    async+concurrent:新开多个线程异步执行
    并发的前提是多线程
    并发和串行是相对于队列来说的,指的是队列中任务的执行顺序,同步和异步针对的是任务执行是否需要立即返回返回值
    同步执行会等待当前队列中的任务执行完毕,才会接着执行后面的代码

    四、两种特殊情况

    主线程中同步执行
    - (void)mainQueueSyncTask {
        NSLog(@"mainQueueSyncTask---start");
        dispatch_queue_t t = dispatch_get_main_queue();
        
        dispatch_sync(t, ^{
            NSLog(@"1---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(t, ^{
            NSLog(@"2---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(t, ^{
            NSLog(@"3---%@",[NSThread currentThread]);
        });
        
        dispatch_sync(t, ^{
            NSLog(@"4---%@",[NSThread currentThread]);
        });
        NSLog(@"mainQueueSyncTask---end");
    }
    

    结果:

    2018-11-22 15:54:56.523 XKQuote[14542:4908219] mainQueueSyncTask---start
    

    原因:
    线程是执行任务的,队列是存放任务的。当主线程执行完主队列中的ABCD...等,走到mainQueueSyncTask方法时,mainQueueSyncTask就相当于主线程正在处理的一个任务,而此时执行到dispatch_sync,此时会在主队列中添加一个任务,暂成为newTask,也就是排在mainQueueSyncTask后面的任务,而同步执行需要马上执行任务,而主线程现在正在执行mainQueueSyncTask这个方法,所以dispatch_sync在等待主线程。而主线程在执行mainQueueSyncTask方法中的dispatch_sync这一步,只有这一步返回了结果,mainThread才会继续往下执行到NSLog(@"end")结束,再去执行newTask,所以形成了相互的等待;

    步骤简析:
    1.mainQueueSyncTask执行NSLog完毕
    2.执行dispatch_sync(),未返回,等待主线程执行后返回结果
    3.主队列等待dispatch_sync()返回后执行mainQueueSyncTask方法中的下一步
    4.循环等待

    非主线程中在主队列中同步执行任务
    - (void)mainQueueSyncTaskInSubThread {
        // initWithBlock方法在10.0以后再能使用
        NSThread *thread = [[NSThread alloc] initWithBlock:^{
            NSLog(@"mainQueueSyncTask---start");
            NSLog(@"%@",[NSThread currentThread]);
            
            dispatch_queue_t t = dispatch_get_main_queue();
            
            dispatch_sync(t, ^{
                NSLog(@"1---%@",[NSThread currentThread]);
            });
            
            dispatch_sync(t, ^{
                NSLog(@"2---%@",[NSThread currentThread]);
            });
            
            dispatch_sync(t, ^{
                NSLog(@"3---%@",[NSThread currentThread]);
            });
            
            dispatch_sync(t, ^{
                NSLog(@"4---%@",[NSThread currentThread]);
            });
            NSLog(@"mainQueueSyncTask---end");
        }];
        [thread start];
    }
    

    结果

    2018-11-22 16:05:43.285 XKQuote[14826:4922979] mainQueueSyncTask---start
    2018-11-22 16:05:43.286 XKQuote[14826:4922979] <NSThread: 0x600000270300>{number = 4, name = (null)}
    2018-11-22 16:05:43.298 XKQuote[14826:4922657] 1---<NSThread: 0x600000075380>{number = 1, name = main}
    2018-11-22 16:05:43.299 XKQuote[14826:4922657] 2---<NSThread: 0x600000075380>{number = 1, name = main}
    2018-11-22 16:05:43.300 XKQuote[14826:4922657] 3---<NSThread: 0x600000075380>{number = 1, name = main}
    2018-11-22 16:05:43.301 XKQuote[14826:4922657] 4---<NSThread: 0x600000075380>{number = 1, name = main}
    2018-11-22 16:05:43.302 XKQuote[14826:4922979] mainQueueSyncTask---end
    

    原因:
    之所以不循环等待,是执行dispatch_sync时,去到了mainThread执行,而当前thread执行的是mainQueueSyncTaskInSubThread方法,当然不会循环等待。特别注意执行dispatch_sync之前的NSLog,表明当前线程不是主线程

    主队列异步执行
    - (void)AsyncTaskWithMainQueue {
        NSLog(@"AsyncTaskWithMainQueue---start");
        NSLog(@"%@",[NSThread currentThread]);
        
        dispatch_queue_t t = dispatch_get_main_queue();
        
        dispatch_async(t, ^{
            NSLog(@"1---%@",[NSThread currentThread]);
        });
        
        dispatch_async(t, ^{
            NSLog(@"2---%@",[NSThread currentThread]);
        });
        
        dispatch_async(t, ^{
            NSLog(@"3---%@",[NSThread currentThread]);
        });
        
        dispatch_async(t, ^{
            NSLog(@"4---%@",[NSThread currentThread]);
        });
        NSLog(@"AsyncTaskWithMainQueue---end");
    }
    

    结果

    2018-11-22 16:20:54.298 XKQuote[17987:4947380] AsyncTaskWithMainQueue---start
    2018-11-22 16:20:54.299 XKQuote[17987:4947380] <NSThread: 0x7faa5bc02090>{number = 1, name = main}
    2018-11-22 16:20:54.299 XKQuote[17987:4947380] AsyncTaskWithMainQueue---end
    2018-11-22 16:20:54.307 XKQuote[17987:4947380] 1---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
    2018-11-22 16:20:54.307 XKQuote[17987:4947380] 2---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
    2018-11-22 16:20:54.308 XKQuote[17987:4947380] 3---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
    2018-11-22 16:20:54.308 XKQuote[17987:4947380] 4---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
    

    原因
    主队列异步执行的区别就是异步会直接返回结果,所以执行完方法之后才会去执行dispatch_async

    相关文章

      网友评论

        本文标题:iOS多线程(一):GCD的基本使用

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