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

一、什么是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---{number = 1, name = main}
2018-11-21 15:25:05.038 XKQuote[51245:4129046] 2---{number = 1, name = main}
2018-11-21 15:25:06.040 XKQuote[51245:4129046] 3---{number = 1, name = main}
2018-11-21 15:25:07.040 XKQuote[51245:4129046] 4---{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---{number = 2, name = (null)}
2018-11-22 15:01:44.514 XKQuote[14265:4858727] asyncTaskWithSerialQueue:2---{number = 2, name = (null)}
2018-11-22 15:01:45.518 XKQuote[14265:4858727] asyncTaskWithSerialQueue:3---{number = 2, name = (null)}
2018-11-22 15:01:46.523 XKQuote[14265:4858727] asyncTaskWithSerialQueue:4---{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---{number = 1, name = main}
2018-11-22 15:05:27.701 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:2---{number = 1, name = main}
2018-11-22 15:05:28.702 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:3---{number = 1, name = main}
2018-11-22 15:05:29.703 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:4---{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---{number = 6, name = (null)}
2018-11-21 16:11:32.372 XKQuote[51304:4187339] 2---{number = 7, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187341] 4---{number = 8, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187340] 3---{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.循环等待

换各种方法:

   dispatch_queue_t t = dispatch_queue_create("serialQueue", 0);
//    dispatch_queue_t t = dispatch_get_main_queue();
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_sync(t, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"xxx");

结果:

2019-06-15 07:04:51.450024+0800 XKSqlite3[64298:2020687] {number = 1, name = main}
2019-06-15 07:04:51.450251+0800 XKSqlite3[64298:2020687] {number = 1, name = main}
2019-06-15 07:04:55.336086+0800 XKSqlite3[64298:2020687] xxx

注意:
1、注意输出,执行的线程都在主线程;
2、成功执行完成,没有发生堵塞;
原因:
1、队列只是存放任务,dispatch_get_main_queue()也只是获取主队列,而不是主线程。
2、在哪个线程执行,是否新开线程执行这些都是GCD自己控制,队列永远是存放任务的,而线程是执行任务的。
3、任务没有存放在朱队列,就不存在排队等待的情况,所以并不会发生堵塞。

非主线程中在主队列中同步执行任务
- (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] {number = 4, name = (null)}
2018-11-22 16:05:43.298 XKQuote[14826:4922657] 1---{number = 1, name = main}
2018-11-22 16:05:43.299 XKQuote[14826:4922657] 2---{number = 1, name = main}
2018-11-22 16:05:43.300 XKQuote[14826:4922657] 3---{number = 1, name = main}
2018-11-22 16:05:43.301 XKQuote[14826:4922657] 4---{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] {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---{number = 1, name = main}
2018-11-22 16:20:54.307 XKQuote[17987:4947380] 2---{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 3---{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 4---{number = 1, name = main}

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

你可能感兴趣的:(iOS多线程(一):GCD的基本使用)