iOS-线程之GCD方式---之同步异步和串行队列并行队列之间的关系
GCD方式是Apple官方推荐实现多线程的方式
但在这之前必须理清楚同步,异步,串行队列,并行队列之间的概念.
同步:即当前的执行程序块不会创建一个新的线程,只能在当前线程中执行.
异步:会在当前的线程之外创建一个新的线程,并在新的线程中执行代码块.
首先声明一点,队列是用来存放即将执行的线程体的.
串行队列:串行队列中的线程满足FIFO(First In First Out),并且只有在先出的线程执行完,后续的线程才能出队列执行.(很可能造成APP的假死状态)
并行队列:并行队列也满足FIFO,只有利用并行队列和异步的方式配合才能实现多线程同时执行(后面会讲到)
下面的代码部分的四种情况
1.串行队列和同步方式(不推荐使用)
1 //1.同步方式向串行队列提交代码 2 //前面的线程执行完成后,才会开始执行后面的线程 3 - (void)testSyncWithSerialQueue 4 { 5 //串行队列 6 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); 7 8 //线程一 9 dispatch_sync(serialQueue, ^(void){ 10 for (int i=0; i<100; i++) { 11 NSLog(@"线程一:%d",i); 12 } 13 }); 14 15 //线程二 16 dispatch_sync(serialQueue, ^(void){ 17 for (int i=0; i<100; i++) { 18 NSLog(@"线程二:%d",i); 19 } 20 }); 21 }
执行结果及结论:---前面的线程执行完成后,才会开始执行后面的线程
2015-08-08 19:59:35.730 TestAsyncAndSync[3187:141197] 线程一:96
2015-08-08 19:59:35.730 TestAsyncAndSync[3187:141197] 线程一:97
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程一:98
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程一:99
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程二:0
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程二:1
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程二:2
2015-08-08 19:59:35.731 TestAsyncAndSync[3187:141197] 线程二:3
2.串行队列和异步方式
1 - (void)testAsyncWithSerialQueue 2 { 3 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); 4 //异步,线程一 5 dispatch_async(serialQueue, ^(void){ 6 for (int i=0; i<100; i++) { 7 NSLog(@"线程1:%d",i); 8 } 9 }); 10 11 //异步:线程二 12 dispatch_async(serialQueue, ^(void){ 13 for (int i=0; i<100; i++) { 14 NSLog(@"线程2:%d",i); 15 } 16 }); 17 }
执行结果及结论:串行队列前面的线程执行完才能执行后面的线程
2015-08-08 20:03:28.391 TestAsyncAndSync[3225:143307] 线程1:97
2015-08-08 20:03:28.391 TestAsyncAndSync[3225:143307] 线程1:98
2015-08-08 20:03:28.391 TestAsyncAndSync[3225:143307] 线程1:99
2015-08-08 20:03:28.391 TestAsyncAndSync[3225:143307] 线程2:0
2015-08-08 20:03:28.391 TestAsyncAndSync[3225:143307] 线程2:1
2015-08-08 20:03:28.392 TestAsyncAndSync[3225:143307] 线程2:2
3.并行队列和同步方式创建线程
1 - (void)testSyncWithConcurrentQueue 2 { 3 dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); 4 //线程一 5 dispatch_sync(concurrentQueue, ^(void){ 6 for (int i=0; i<100; i++) { 7 NSLog(@"线程一:%d",i); 8 } 9 }); 10 11 //线程一 12 dispatch_sync(concurrentQueue, ^(void){ 13 for (int i=0; i<100; i++) { 14 NSLog(@"线程二:%d",i); 15 } 16 }); 17 }
结果和结论:先执行线程一,再执行线程二
2015-08-08 20:06:19.111 TestAsyncAndSync[3257:144554] 线程一:97
2015-08-08 20:06:19.111 TestAsyncAndSync[3257:144554] 线程一:98
2015-08-08 20:06:19.111 TestAsyncAndSync[3257:144554] 线程一:99
2015-08-08 20:06:19.112 TestAsyncAndSync[3257:144554] 线程二:0
2015-08-08 20:06:19.112 TestAsyncAndSync[3257:144554] 线程二:1
2015-08-08 20:06:19.112 TestAsyncAndSync[3257:144554] 线程二:2
4.并行队列和异步方式
1 - (void)testAsyncWithConcurrentQueue 2 { 3 dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); 4 //异步,线程一 5 dispatch_async(concurrentQueue, ^(void){ 6 for (int i=0; i<100; i++) { 7 NSLog(@"线程1:%d",i); 8 } 9 }); 10 11 //异步:线程二 12 dispatch_async(concurrentQueue, ^(void){ 13 for (int i=0; i<100; i++) { 14 NSLog(@"线程2:%d",i); 15 } 16 }); 17 18 }
执行结果及结论:线程一和线程二同时执行
2015-08-08 20:07:48.318 TestAsyncAndSync[3283:145696] 线程1:0
2015-08-08 20:07:48.318 TestAsyncAndSync[3283:145693] 线程2:0
2015-08-08 20:07:48.319 TestAsyncAndSync[3283:145693] 线程2:1
2015-08-08 20:07:48.319 TestAsyncAndSync[3283:145693] 线程2:2
2015-08-08 20:07:48.319 TestAsyncAndSync[3283:145693] 线程2:3
2015-08-08 20:07:48.319 TestAsyncAndSync[3283:145696] 线程1:1
再解释上述的四种情况:不得不说,线程队列是一种神奇的东西,似乎无法控制,又有迹可循...
为什么会造成上面的四种情况呢:
首先来说说第四种情况,异步方式创建线程并使用并行队列存放.主要是因为并行队列允许队列中的线程体出队列后,立马下一个线程体就可以出队列.而使用异步的方式,每一个出来的线程体会创建一个新的线程执行对应的代码块.所以就产生两个线程同时执行的情况.(但是也有让你感到无力的,你无法完全的控制两个线程,即使先出队列线程,也不一定先执行完,线程执行的快慢主要在于两个线程抢占系统资源获得的多少)
第一种和第二种情况:由于串行只允许先进队列的线程,出队列后执行完才能再下一个线程出队列,所以一定是有序(根据进队列的先后)
第三种情况:并行同步方式:虽然并行队列允许多个线程同时出队列(还是先进先出的方式),但是先出的线程不会创建新的线程,只能在当前线程中执行任务,由于当前线程只有一个,所有即使同时出队列多个线程,也只能出于等待.