多线程GCD的使用

         GCD——Grand Central Dispatch 是基于C语言的框架,可以充分利用多核,也是苹果官方推荐使用的多线程技术。

 

         GCD是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread,NSOperation的高效和强大的技术,GCD是基于C语言的

         GCD是苹果公司为多核的并行运算提出的解决方案

         GCD会自动利用更多的CPU内核(比如双核、四核)

         GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
 
多线程里面概念性的东西很多也很难记,所以一定要好好理解。还是通过代码,在温习温习吧。相同的代码写多次,虽然有时很枯燥,可每次都会有不同的体会和领悟。走起!
viewController中:
 1 #import "ViewController.h"
 2 
 3 @interface ViewController ()
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 /*
10 //写之前,再来温习温习。
11  GCD的使用:
12  一 :队列
13  1.串行队列:添加到队列中的任务是一个一个执行的
14  2.并发(行)队列:添加到队列中的任务是多个同时执行的
15  3.主队列:里面的任务都是在主线程执行的。
16  4.全局队列:并行(发)队列
17  
18  二:同步、异步
19  1、同步:需要后面的任务等待,不会开启新的线程,会直接使用当前的线程
20  
21  2、异步:不需要后面的任务等待,会开启新的线程
22  */
23 
24 - (void)viewDidLoad {
25     [super viewDidLoad];
26     
27     /*---------创建并发队列---------*/
28 
29     //1.创建并行队列
30     dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
31     
32     //2.获取全局队列(并行队列)
33     /*优先级<#long identifier#>
34      DISPATCH_QUEUE_PRIORITY_HIGH
35      DISPATCH_QUEUE_PRIORITY_DEFAULT
36      DISPATCH_QUEUE_PRIORITY_LOW
37      DISPATCH_QUEUE_PRIORITY_BACKGROUND
38      */
39     
40     dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
41     
42     //(1)在并发队列添加异步任务
43 
44     dispatch_async(queue2, ^{
45     
46                   for (int i = 0; i < 50 ;i ++) {
47                 
48                 NSLog(@"1---------1");
49             }
50         
51         
52     });
53     
54     dispatch_async(queue2, ^{
55         
56         
57             for (int i = 0; i < 50 ;i ++) {
58                 
59                 NSLog(@"2---------2");
60             }
61         
62         
63     });

打印结果:

 

通过打印结果我们可以看出:
(1)并发队列异步添加任务会开多条线程,执行顺序是没有先后(同时执行)
 
看完并发队列的异步添加,让我们再来看看并发队列的同步添加:

 

 1 dispatch_sync(queue2, ^{
 2     
 3         @autoreleasepool {
 4             for (int i = 0; i < 50 ;i ++) {
 5                 
 6                 NSLog(@"1---------1");
 7             }
 8         }
 9     });
10     
11     
12     dispatch_sync(queue2, ^{
13         
14         @autoreleasepool {
15             for (int i = 0; i < 50 ;i ++) {
16                 
17                 NSLog(@"2---------2");
18             }
19         }
20     });

这个打印结果相信不用说,我们都知道肯定是先执行1  在执行2

其实执行问题好回答,关键是此时的任务是在那个线程完成的,相信如果你对同步添加的概念如果十分清楚的话一定能回答对,没有错。这些任务是在主线程中完成的。并不是在queue2中完成的。让我们看图吧,有图有真相
通过以上分析我们可以看出:
(1)在并发队列中同步添加任务,不会开启新的线程,会直接使用当前线程,
(2)并且,我们添加的任务是添加到主线程。并不是表面现象的queue2。
 
 
看完并发(行)队列,让我们来看看串行队列吧。
 1     /*---------创建串行----------*/
 2     
 3     dispatch_queue_t queue = dispatch_queue_create("queue3", DISPATCH_QUEUE_SERIAL);
 4     
 5     //向串行队列异步添加任务
 6     dispatch_async(queue, ^{
 7     
 8         for (int i=0; i<50; i++) {
 9             NSLog(@"🐷....i:%d",i);
10         }
11 
12     });
13     
14     dispatch_async(queue, ^{
15     
16         for (int i=0; i<50; i++) {
17             NSLog(@"🐶....i:%d",i);
18         }
19 
20     });

打印结果:

 尽管是异步添加任务,但是该队列是串行队列,所以猪 先被执行,然后才执行狗。

如果此时我们再在viewDidLoad中也就是在狗的for训话下面添加一个for循环的话你能想象出结果吗?

1     for (int i=0; i<100; i++) {
2         NSLog(@"🐱....i:%d",i);
3     }

打印结果:

不难看出猫与(狗和猪)是同时执行的。而(猪和狗)则是猪先执行,狗在执行。例如猪和狗排了一个队,而猫自己排了一个队。
 
继续介绍:

向串行队列同步添加任务

    dispatch_sync(queue, ^{
        
        for (int i=0; i<50; i++) {
            NSLog(@"🐶....i:%d",i);
        }
    });
    
    dispatch_sync(queue, ^{
    
        for (int i=0; i<100; i++) {
            NSLog(@"🐱....i:%d",i);
        }
        
    });
    
    for (int i=0; i<100; i++) {
        NSLog(@"🐷....i:%d",i);
    }

 运行结果毫无疑问。狗-----》猫----------》猪;时刻记着同步添加任务,不会开启新的线程,会直接使用当前线程。那么肯定这三个任务也是在当前的主线程。

 

介绍完这些,还有一个重要的东西那就是死锁

让我们来看一下

获取主队列:

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

分配任务:

1     NSLog(@"任务开始啦!!!");
2     //同步添加任务
3     dispatch_sync(mainQueue, ^{
4     
5         NSLog(@"任务添加");
6         
7     });
8     
9     NSLog(@"结束");

毫无疑问第一个打印肯定是  第一行的“任务开始啦!!!”,那么接下来走第三行代码,因为是Block所以第五行的代码要在第九行的打印执行结束后才能被执行(block回调),又因为是同步添加任务,所以第九行代码要在上面的任务执行完才能开始。所以编译器犹豫不知道该执行那一个。会造成死锁。

打印结果:

 

总结:(1)在使用主队列时,绝对不可以在主队列中同步添加任务,会造成死锁。

         (2)并发队列:同步添加不会开启新的线程,异步添加会开启多条线程。

         (3)串行队列:同步添加不会开启新的线程,异步添加会开启一条线程。

         (4)由(2)和(3)得出结论同步添加任务,不具备开启线程的能力。异步添加任务开启线程的条数由当前队列决定,串行队列开启一条线程,并行队列开启多条。

 

 

 
posted @ 2015-09-20 15:03  悲了伤的老王  阅读(251)  评论(0编辑  收藏  举报