讲解GCD的资料看了好多,但都没有解决心中的疑惑:

  1.主队列只有一个线程,那么同步和异步执行有什么区别?同步主线程会造成线程死锁,异步不会,为什么呢?

  2.同步执行串行队列和同步执行并发队列,有什么区别?同步执行,是在当前线程中执行队列中的任务,就意味着任务都在一条线程中执行,不可能多任务同时执行啊。

  3.在主线程中同步执行串行队列,为什么就不造成线程死锁呢?

有疑不解,如鲠在喉。有疑惑就代表学得不到位,概念理解不够。因此,我开始重头学习GCD,理清这些基础概念。

 

有4个术语比较容易混淆:同步、异步、并发、串行

同步和异步决定了要不要开启新的线程

  同步:在当前线程中执行任务,不具备开启新线程的能力

  异步:在新的线程中执行任务,具备开启新线程的能力

并发和串行决定了任务的执行方式

  并发:多个任务并发(同时)执行

  串行:一个任务执行完毕后,再执行下一个任务

组合一下:

  1. 同步执行串行队列
  2. 同步执行并发队列
  3. 异步执行串行队列
  4. 异步执行并发队列
  5. 同步执行主队列
  6. 异步执行主队列

我加入了主队列(只有一条线程的串行队列),是因为它和一般的串行队列有些区别。下面我就对这6种情况逐个分析。

1.同步执行串行队列:在当前线程中,逐一执行队列中的任务。

2.同步执行并发队列:同1

3.异步执行串行队列:开启一条新线程,逐一执行队列中的任务。

4.异步执行并发队列:开启多条线程,同时执行队列中的多个任务。

先理清这四种情况的嵌套执行,在讲主线程的两种情况。

下面就是大堆代码了,对照代码和打印结果进行思考,看有没有自己觉得解释不通的。

demo地址:https://github.com/jiliuliu/FoundationOC

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_queue_t backgroundSerialQueue = dispatch_queue_create("backgroundSerialQueue", DISPATCH_QUEUE_SERIAL);
        
        dispatch_queue_t serialQueue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
        dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
        
        //避开主线程,单独开启一个线程做测试
        dispatch_async(backgroundSerialQueue, ^{
            NSLog(@"%@", [NSThread currentThread]);
            
            dispatch_sync(serialQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(serialQueue)1");
            });
            dispatch_sync(serialQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(serialQueue)2");
            });
            dispatch_sync(serialQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(serialQueue)3");
            });
            
            NSLog(@"************************");
            
            dispatch_sync(concurrentQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(concurrentQueue)1");
            });
            dispatch_sync(concurrentQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(concurrentQueue)2");
            });
            dispatch_sync(concurrentQueue, ^{
                [NSThread sleepForTimeInterval:0.01];
                NSLog(@"dispatch_sync(concurrentQueue)3");
            });
            
        });
    }
    NSLog(@"----exit----");
    return 0;
}

打印结果:

----exit----
<NSThread: 0x10064f1b0>{number = 2, name = (null)}

这不对啊(捂脸),于是修改下:

void GCDTest_createQueue(void (^block) (dispatch_queue_t, dispatch_queue_t)) {
    dispatch_queue_t backgroundSerialQueue = dispatch_queue_create("backgroundSerialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_queue_t serialQueue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    //避开主线程,单独开启一个线程做测试
    dispatch_async(backgroundSerialQueue, ^{
        NSLog(@"%@", [NSThread currentThread]);
        
        block(serialQueue, concurrentQueue);
        
        dispatch_barrier_sync(serialQueue, ^{
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_barrier_sync(concurrentQueue, ^{
            dispatch_semaphore_signal(semaphore);
        });
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

上面这个方法单独列出来,下面会多次调用。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void GCDTest1(void);
        GCDTest1();
    }
    NSLog(@"----exit----");
    return 0;
}

void GCDTest1(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"%@:dispatch_sync(serialQueue)1", [NSThread currentThread]);
        });
        NSLog(@"dispatch_sync(serialQueue)1--");
        
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"dispatch_sync(serialQueue)2");
        });
        NSLog(@"dispatch_sync(serialQueue)2--");
        
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"dispatch_sync(serialQueue)3");
        });
        NSLog(@"dispatch_sync(serialQueue)3--");
        
        NSLog(@"************************");
        
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"%@:dispatch_sync(concurrentQueue)1", [NSThread currentThread]);
        });
        NSLog(@"dispatch_sync(concurrentQueue)1--");
        
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"dispatch_sync(concurrentQueue)2");
        });
        NSLog(@"dispatch_sync(concurrentQueue)2--");
        
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.01];
            NSLog(@"dispatch_sync(concurrentQueue)3");
        });
        NSLog(@"dispatch_sync(concurrentQueue)3--");
    });
}

 

打印结果:

<NSThread: 0x1004601f0>{number = 2, name = (null)}
<NSThread: 0x1004601f0>{number = 2, name = (null)}:dispatch_sync(serialQueue)1
dispatch_sync(serialQueue)1--
dispatch_sync(serialQueue)2
dispatch_sync(serialQueue)2--
dispatch_sync(serialQueue)3
dispatch_sync(serialQueue)3--
************************
<NSThread: 0x1004601f0>{number = 2, name = (null)}:dispatch_sync(concurrentQueue)1
dispatch_sync(concurrentQueue)1--
dispatch_sync(concurrentQueue)2
dispatch_sync(concurrentQueue)2--
dispatch_sync(concurrentQueue)3
dispatch_sync(concurrentQueue)3--
----exit----

对,应该是这样的。

那为什么前面的不对呢?这是因为我们在主线程中开启了新线程,而主线程还没等新线程中的任务执行完成就已经执行到return了,然后程序退出。在GCDTest_createQueue函数中,通过dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block)函数得到queue队列执行完所有任务的状态,加入dispatch_semaphore,让主线程等待新线程中所有任务执行完,才往下执行return。因此,通过GCDTest_createQueue函数我们可以让我们的测试在一个新线程中进行。

通过这个测试,我们可以看到它们

  1. 同步执行串行队列
  2. 同步执行并发队列

都是在当前线程逐一执行任务。那它们就真的一样了吗?先留着这个疑问。

继续看代码:

void GCDTest2(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_sync(serialQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            //运行后程序卡着这里
            dispatch_sync(serialQueue, ^{ //任务2
                NSLog(@"%@:---2", [NSThread currentThread]);
            });
        });
    });
}

运行后程序卡住了。嵌套同步串行,导致任务1和任务2相互等待,造成线程死锁。

 

下面我们把外面的串行队列改成并发队列试试:

void GCDTest3(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        //只在这里把GCDTest2中的serialQueue改成concurrentQueue
        dispatch_sync(concurrentQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            dispatch_sync(serialQueue, ^{ //任务2
                NSLog(@"%@:---2", [NSThread currentThread]);
            });
        });
    });
}

运行结果:

<NSThread: 0x10063f9c0>{number = 2, name = (null)}
<NSThread: 0x10063f9c0>{number = 2, name = (null)}:---1
<NSThread: 0x10063f9c0>{number = 2, name = (null)}:---2
----exit----

惊不惊喜,意不意外。好吧,可能你感觉很平淡,但我挺意外的,因为我通过GCDTest1和GCDTest2得出中推断出来,同步执行串行队列和同步执行并发队列是一样的,也会因任务1和任务2相互等待,造成死锁。但为什么没有呢?我也想不通,于是我执行了下面个有点疯狂的函数的测试:

void GCDTest4(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        //只在这里把GCDTest2中的serialQueue改成concurrentQueue
        dispatch_sync(concurrentQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            //运行后程序卡着这里
            dispatch_sync(serialQueue, ^{ //任务2
                NSLog(@"%@:---2", [NSThread currentThread]);
                dispatch_sync(concurrentQueue, ^{
                    NSLog(@"%@:---3", [NSThread currentThread]);
                    //最终程序卡在这里
                    dispatch_sync(serialQueue, ^{
                        NSLog(@"%@:---4", [NSThread currentThread]);
                    });
                });
            });
        });
    });
}

程序在我标注的地方卡死了。虽然想不通,但至少我得出三个结论:

  1.嵌套同步串行队列,会造成死锁。

  2.嵌套同步并发队列,可以良好的运行。

  3.同步串行队列和同步并发队列是有一定区别的。但这个区别的本质是什么呢?

不管了,继续看代码:

void GCDTest5(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--1", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--2", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--3", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--4", [NSThread currentThread]);
        });
    });
}

运行结果:

<NSThread: 0x10051af00>{number = 2, name = (null)}:背景线程
<NSThread: 0x10051c5c0>{number = 3, name = (null)}-async-serialQueue--1
<NSThread: 0x10051c5c0>{number = 3, name = (null)}-async-serialQueue--2
<NSThread: 0x10051c5c0>{number = 3, name = (null)}-async-serialQueue--3
<NSThread: 0x10051c5c0>{number = 3, name = (null)}-async-serialQueue--4

和我预料的一样,异步串行队列,开启一条新线程,按顺序逐一执行队列中的任务。但我产生了一个好奇,为什么都是number = 3呢?难道是串行队列会锁定一个线程?于是我把代码改成这样:

void GCDTest5(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--1", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--2", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--3", [NSThread currentThread]);
        });
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-sync-serialQueue--4", [NSThread currentThread]);
        });
        [NSThread sleepForTimeInterval:0.02];
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--5", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--6", [NSThread currentThread]);
        });
    });
}

运行结果:

<NSThread: 0x100506530>{number = 2, name = (null)}:背景线程
<NSThread: 0x1005712b0>{number = 3, name = (null)}-async-serialQueue--1
<NSThread: 0x1005712b0>{number = 3, name = (null)}-async-serialQueue--2
<NSThread: 0x1005712b0>{number = 3, name = (null)}-async-serialQueue--3
<NSThread: 0x100506530>{number = 2, name = (null)}-sync-serialQueue--4
<NSThread: 0x1005712b0>{number = 3, name = (null)}-async-concurrentQueue--5
<NSThread: 0x10040b6d0>{number = 4, name = (null)}-async-serialQueue--6
----exit----

看见没,“number = 3”在后面被“async-concurrentQueue”抢了去,“async-serialQueue”只能去用“number = 4”了,在异步串行队列的任务中插入一个同步串行任务,同步串行又会回到当前线程中去执行。看来队列并不会跟线程有绑定关系。

继续看代码:

void GCDTest6(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--1", [NSThread currentThread]);
        });
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--2", [NSThread currentThread]);
        });
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--3", [NSThread currentThread]);
        });
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--4", [NSThread currentThread]);
        });
        
    });
}

运行结果:

<NSThread: 0x10043a2d0>{number = 2, name = (null)}:背景线程
<NSThread: 0x10070e560>{number = 5, name = (null)}-async-concurrentQueue--3
<NSThread: 0x100643820>{number = 4, name = (null)}-async-concurrentQueue--2
<NSThread: 0x100516ad0>{number = 6, name = (null)}-async-concurrentQueue--4
<NSThread: 0x10043ab80>{number = 3, name = (null)}-async-concurrentQueue--1
----exit----

异步并发队列,开启多条线程执行任务。这执行顺序是否很乱,好吧,我也觉得好乱,“number”和任务编号都乱了。但我突然灵光一显,发现了里面其实隐藏了一个规律:每个任务的“number”减去任务编号都等于2,说明异步并发队列,也就是按队列中任务添加的顺序执行的,但每个任务的执行耗时有差异,只因为这个耗时差异才导致打印的无序。

回想GCDTest2中测试的嵌套同步串行队列会造成死锁的情况,感觉有必要加入异步再测试下,修改下代码:

void GCDTest7(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(serialQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            dispatch_async(serialQueue, ^{ //任务2
                NSLog(@"%@:---2", [NSThread currentThread]);
            });
            NSLog(@"---3");
        });
    });
}

运行结果:

<NSThread: 0x10051bf50>{number = 2, name = (null)}:背景线程
<NSThread: 0x102825720>{number = 3, name = (null)}:---1
---3
----exit----
<NSThread: 0x102825720>{number = 3, name = (null)}:---2

一个意外的结果,“exit”出现在了打印中间,这时候main函数已经return了,GCDTest_createQueue函数为什么没有准确监控到serialQueue中全部任务执行完成的状态?为什么main函数return了还能打印“---2”?为什么呢?我也想不通,读者自己想吧。但从这个现象推测两点,dispatch_barrier_sync对队列嵌套执行的监控可能是不准确的;main函数return了,系统应该也不能立即回收程序的进程资源,这应该是个耗时操作,在任务2中如果加入耗时操作,“---2”就打印不出。除了这两个问号之外,我从此列中还知道:“---2”在后面执行,说明任务2是等待任务1执行完后才开始执行,这正是串行队列的特性。

继续看代码:

void GCDTest8(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
            dispatch_async(serialQueue, ^{ //任务1
                NSLog(@"%@:---1", [NSThread currentThread]);
                //运行后程序卡着这里
                dispatch_sync(serialQueue, ^{ //任务2
                    NSLog(@"%@:---2", [NSThread currentThread]);
                });
            });
        });
    });
}

马上执行,而任务1正在执行中,串行队列又不能同时执行多个任务,没法了,程序只能卡死了。

回到主线程。

5.同步执行主队列:线程死锁,同GCDTest2中,同步串行队列嵌套执行中的分析。所以关于主队列的操作指引异步执行主队列。

 6.异步执行主队列:是一种特殊的异步串行队列,等待主线程空闲了就执行异步添加的任务,但当我看了这篇关于runloop的文章:https://blog.ibireme.com/2015/05/18/runloop/   我就纠结了。

哎,经过了上面的测试,到了主线程这里,反而不知道说什么了。

看代码:

void GCDTest10(void) {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"---1");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"---2");
        });
        NSLog(@"---3");
    });
    NSLog(@"---4");
}

运行结果:

---4
----exit----

main函数这怂货又在没执行完我的任务的时候就跑了,气死我了。修改下:

void GCDTest10(void) {
    dispatch_async(dispatch_get_main_queue(), ^{
        [NSThread sleepForTimeInterval:0.02];
        NSLog(@"%@:---1", [NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@:---2", [NSThread currentThread]);
        });
        NSLog(@"%@:---3", [NSThread currentThread]);
    });
    NSLog(@"%@:---4", [NSThread currentThread]);
}

 

通过启动主runloop我让主线程常驻,程序一直保持运行状态,哈哈,这样就能让我们安心测试了?

运行后打印结果:

<NSThread: 0x10050a500>{number = 1, name = main}:---4
<NSThread: 0x10050a500>{number = 1, name = main}:---1
<NSThread: 0x10050a500>{number = 1, name = main}:---3
<NSThread: 0x10050a500>{number = 1, name = main}:---2

分析得到,异步执行主队列,任务按添加顺序一个等一个依次执行。但有一点和普通的异步串行不一样,主队列中的任务永远只在主线程里执行,普通的异步串行并不这样,可参见GCDTest5中的分析。

那接下来干嘛呢,好像没什么讲的了。那让我们来看看GCD的一些案例吧。

SDWebimage中的一个宏:

#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
    if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\
        block();\
    } else {\
        dispatch_async(queue, block);\
    }
#endif

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif

额...,我错了,这是两个宏。

作用:如果当前是在主线程中,则直接执行,不然异步执行。

在YYKit中有一样功能的函数:

static inline void dispatch_sync_on_main_queue(void (^block)()) {
    if (pthread_main_np()) {
        block();
    } else {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

下面代码展示监控[UITableView reloadData]执行完成的状态。

[tableView reloadData];
    dispatch_async(dispatch_get_main_queue(), ^{
        //获取到reloadData执行完成的状态。。
    });

下面的是总结,其实通过这些测试,我发现有些地方我进入了理解误区,使问题复杂化了,同时对一些概念有了深入的认识。

 

总结:

 

NO.1

void GCDTest2(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_sync(serialQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            //运行后程序卡着这里
            dispatch_sync(serialQueue, ^{ //任务2
                NSLog(@"%@:---2", [NSThread currentThread]);
            });
        });
    });
}

void GCDTest3(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        //只在这里把GCDTest2中的serialQueue改成concurrentQueue
        dispatch_sync(concurrentQueue, ^{ //任务1
            NSLog(@"%@:---1", [NSThread currentThread]);
            dispatch_sync(serialQueue, ^{ //任务2
                [NSThread sleepForTimeInterval:0.02];
                NSLog(@"%@:---2", [NSThread currentThread]);
            });
            NSLog(@"---3");
        });
    });
}
前面分析这两个列子的时候,我对GCDTest3没有和GCDTest2一样造成线程死锁,感到很惊讶,现在再看像这样想反而是没有道理的。任务1和任务2分别在不同的队列中执行,是无法形成同一队列中的多个任务相互等待关系。到时有这种想法,是因为那是的关注点在线程身上,任务他们都是在同一线程中执行,必然会造成死锁。

NO.2

void GCDTest11(void) {
    NSLog(@"---------GCDTest11-------");
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--1", [NSThread currentThread]);
        });
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--2", [NSThread currentThread]);
        });
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-sync-concurrentQueue--3", [NSThread currentThread]);
        });
        NSLog(@"------space------");
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-concurrentQueue--4", [NSThread currentThread]);
        });
    });
}

void GCDTest12(void) {
    NSLog(@"\n---------GCDTest12-------");
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.04];
            NSLog(@"%@-async-serialQueue--1", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"%@-async-serialQueue--2", [NSThread currentThread]);
        });
        dispatch_sync(serialQueue, ^{
       //可以获取到之前任务都执行完成的状态
            NSLog(@"%@-sync-serialQueue--3", [NSThread currentThread]);
        });
        dispatch_async(serialQueue, ^{
            NSLog(@"%@-async-serialQueue--4", [NSThread currentThread]);
        });
    });
}

运行结果:

---------GCDTest11-------
<NSThread: 0x100581e20>{number = 2, name = (null)}:背景线程
<NSThread: 0x100581e20>{number = 2, name = (null)}-sync-concurrentQueue--3
------space------
<NSThread: 0x10070dc80>{number = 4, name = (null)}-async-concurrentQueue--2
<NSThread: 0x100602060>{number = 3, name = (null)}-async-concurrentQueue--1
<NSThread: 0x10070dc80>{number = 4, name = (null)}-async-concurrentQueue--4

---------GCDTest12-------
<NSThread: 0x100581e20>{number = 2, name = (null)}:背景线程
<NSThread: 0x10070dc80>{number = 4, name = (null)}-async-serialQueue--1
<NSThread: 0x10070dc80>{number = 4, name = (null)}-async-serialQueue--2
<NSThread: 0x100581e20>{number = 2, name = (null)}-sync-serialQueue--3
<NSThread: 0x10070dc80>{number = 4, name = (null)}-async-serialQueue--4

GCDTest11中分析出:异步和同步的区别是是否开启线程,同时也意味着dispatch_async会一会儿执行block中任务,dispatch_sync会立即执行。

NO.3

  同步时,串行和并发执行效果相同?

  有相同,所有不同。

void GCDTest13(void) {
    NSLog(@"---------GCDTest13-------");
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--1");
        });
        NSLog(@"----");
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--2");
        });
        NSLog(@"----");
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--3");
        });
        NSLog(@"----");
        dispatch_sync(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--4");
        });
        NSLog(@"----");
    });
}

void GCDTest14(void) {
    NSLog(@"\n---------GCDTest14-------");
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--1");
        });
        NSLog(@"----");
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--2");
        });
        NSLog(@"----");
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--3");
        });
        NSLog(@"----");
        dispatch_sync(serialQueue, ^{
            [NSThread sleepForTimeInterval:0.02];
            NSLog(@"--4");
        });
        NSLog(@"----");
    });
}

运行结果:

---------GCDTest13-------
<NSThread: 0x1006387c0>{number = 2, name = (null)}:背景线程
--1
----
--2
----
--3
----
--4
----

---------GCDTest14-------
<NSThread: 0x1006387c0>{number = 2, name = (null)}:背景线程
--1
----
--2
----
--3
----
--4
----

这样是相同的。

不同点:

void GCDTest15(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
            dispatch_sync(serialQueue, ^{ //任务1
                NSLog(@"%@:---1", [NSThread currentThread]);
                //运行后程序卡着这里
                dispatch_sync(serialQueue, ^{ //任务2
                    NSLog(@"%@:---2", [NSThread currentThread]);
                });
                NSLog(@"--3");
            });
        });
    });
}

卡死。

void GCDTest16(void) {
    GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
        GCDTest_createQueue(^ (dispatch_queue_t serialQueue, dispatch_queue_t concurrentQueue) {
            dispatch_sync(concurrentQueue, ^{ //任务1
                NSLog(@"%@:---1", [NSThread currentThread]);
                dispatch_sync(concurrentQueue, ^{ //任务2
                    NSLog(@"%@:---2", [NSThread currentThread]);
                });
                NSLog(@"--3");
            });
            NSLog(@"--4");
        });
    });
}

运行结果:

<NSThread: 0x1004008f0>{number = 2, name = (null)}:背景线程
<NSThread: 0x10060e870>{number = 3, name = (null)}:背景线程
<NSThread: 0x10060e870>{number = 3, name = (null)}:---1
<NSThread: 0x10060e870>{number = 3, name = (null)}:---2
--3
--4

当我们嵌套执行时,差异性就出来了。虽然都是同步,但串行队列需要等待前面添加的任务执行完才能执行,(拟人化点:任务1正在执行,但还没执行完,任务2就来对任务1说我事挺急的你先等等,让我先执行完了你再执行,但任务1说不行,我也非常急,结果他们互不相让,结果就是谁都没法做自己的事)。但在并发队列中就非常礼貌了,任务1对任务2说,你急,你先来,我等你执行完了再执行,没事的。

 

啊啊啊,就这样吧。虽然很啰嗦,逻辑也不严谨,但应该不至于成为毒鸡汤吧。自己也算是认真写了,对于之前的疑惑也解决了。至于GCDTest7的疑问就看有没有哪位路过的大神好心帮我解答下。