示例1
- (void)surpassNum
{
while (self.num < 500) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"num is %d",self.num);
}
复制代码
结果:打印结果为>=500
分析:
-
当首次进入循环时,self.num = 0,此时创建一个异步任务,但是这个任务并不一定是立马执 行,会等待先出的调度,此时就会进入下一次循环,由于任务为执行,所以self.num++也就未 执行,所以第二次循环时,self.num还是等于0,此时又会创建一个新的异步任务,以此类推, 至少都会常见500条异步任务
-
由于while循环中使用了self.num<500作为终止条件,所以只有当self.num >=500 时才能跳出循环,执行打印
-
在跳出循环执行打印的中间时间,可能存在多个异步任务执行了,也就相当于self.num++被执行了N次
-
所以打印结果必须 >=500
扩展:如果把 dispatch_async 换成 dispatch_sync 同步任务,则打印结果必定为 500,因为同步任务会堵塞线程, self.num++ 没执行完毕之前,下一次循环就不可能执行。
示例2
- (void)fixNum
{
for(int i= 0; i < 1000; i++){
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"fix num is %d", self.num);
}
复制代码
结果: 打印结果0-999 分析:
-
这里使用了for循环,并且使用了临时变量i,而不是self.num来进行判断,self.num和循环没有关系, 所以这里只会执行999次循环,也就是创建了999个异步任务
-
当i== 1000时for循环终止,此时虽然创建了999个异步任务,但是这些任务执行完毕了吗? 显然没有,需要等待线程来调度;所以在打印之前,到底有多少个任务能够被执行,这个不确定, 可能一个任务都没执行,可能都执行完毕,那么打印结果就有可能是0-999
-
虽然理论上是0-999,但是打印结果还是会趋近于999
示例3
- (void)asynDemo
{
dispatch_queue_t queue = dispatch_queue_create("com.qihu", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"0");
dispatch_async(queue, ^{
NSLog(@"4");
});
dispatch_async(queue, ^{
NSLog(@"5");
});
dispatch_async(queue, ^{
NSLog(@"6");
});
}
复制代码
问:上面的打印结果可能为什么?
- A: 1230456
- B: 1234560
- C: 3120465
- D: 2134560
答: A和C 分析
- 任务3为同步任务,同步任务有个特性就是会阻塞线程的执行,所以在任务3未执行完毕之前,任务0以及之后的任务都会处于阻塞状态,所以3必定在0之前打印
- 然后根据函数的按顺序执行的规律,任务0必定会在 4、5、6 之前进行打印
- 异步任务之间是无序的,所以 1、2、3 之间顺序不定,4、5、6 之间顺序也是不定
如果 queue 是 DISPATCH_QUEUE_SERIAL 类型的串行队列的话则答案是 A
示例4
- (void)barrierTest
{
dispatch_queue_t queue = dispatch_queue_create("com.barrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"3");
});
dispatch_async(queue, ^{
NSLog(@"4");
});
}
复制代码
结果:
1234 或 2134
分析:
- queue 是一个 DISPATCH_QUEUE_CONCURRENT 类型的并发队列,所以任务1和任务2顺序是不定的
2. 任务3使用了 dispatch_barrier_async 栅栏函数来创建任务,它有个特点,就是会将前后任
务进行隔离,任务1和任务2必须都执行完了才会执行任务3,任务4必须等任务3执行完了才能执行
3. 所以任务3在任务1和任务2之后,但是在任务4之前
示例5
- (void)asynDemo1
{
dispatch_queue_t queue = dispatch_queue_create("com.demo", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_async(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
复制代码
结果:
15243
分析:
- 按执行顺序,先打印1
2. dispatch_async创建了异步线程,在后台等待,继续往下执行打印5
3. 异步任务被调用后,先打印2,然后创建一个新异步任务等待调度执行,继续往下执行打印4
4. 最后打印3
示例6
- (void)syncdemo2 {
dispatch_queue_t queue = dispatch_queue_create("com.demo", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{ NSLog(@"3"); });
NSLog(@"4");
});
NSLog(@"5");
}
复制代码
结果:
15234
分析:
- 按顺序执行,先打印 1
2. dispatch_async 创建了异步任务,在后台等待执行,继续往下执行打印 5
3. 异步任务被调用后,先打印 2
4. 创建一个同步任务堵塞线程,等待同步任务执行完毕后才能继续往下执行,所以打印 3
5. 最后打印 4
示例7
- (void)deadLockTest
{
dispatch_queue_t queue = dispatch_queue_create("com.demo", NULL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
复制代码
结果:
152崩溃
分析:
- 按顺序执行,先打印1
2. dispatch_async创建了异步任务,在后台等待执行,继续往下执行打印5
3. 异步任务被调用,先打印2
4. 创建一个同步任务3,由于queue是串行队列,任务3需要等待异步任务执行完毕后才能执行,但是异步任务 又需要等待任务3执行完毕后才能继续往下执行打印4,你依赖我,我依赖你,这里就造成了死锁,最终导致 EXC_BAD_INSTRUCTION 异常错误