zoukankan      html  css  js  c++  java
  • IOS多线程之GCD

    相比较NSOperation和NSThread,GCD提供了更简单的操作实现多线程,多线程下也无需创建自动释放池,而且GCD开发只有两个步骤

    1 创建队列

    2 提交任务到队列

    队列

    GCD创建的队列有两种,一种是串行队列,一种是并行队列,在串行队列中每次只执行一个任务,依次执行下去,而在并行队列中每次可以同时执行多个任务

    //获取当前的队列
    dispatch_queue_t queue = dispatch_get_current_queue();

    可以通过以下两种方式可以获得串行队列

    dispatch_queue_t serialqueue1 = dispatch_get_main_queue();
        
    dispatch_queue_t serialqueue2 = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    //获取队列字符串标签
    char *label = dispatch_queue_get_label(serialqueue2);

    第一种方式获取主线程关联的队列,第二种方式自己创建了一个串行队列

    通过以下两种方式可以获得并行队列

        //获取系统全局并发队列
        //第一个参数接受DISPATCH_QUEUE_PRIORITY_HIGH  DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND
        //第二个参数为了以后扩展,只需传入0
        dispatch_queue_t concurrent1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        //自己创建并发队列
        dispatch_queue_t concurrent2 = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);

    任务提交

    任务提交有两种方式,同步提交和异步提交

    可以使用代码块或者函数的方式实现任务的异步提交

    当我们把任务异步提交到并行队列,主线程串行队列以及自定义串行队列中时会有以下不同的结果

    异步提交代码一:(自定义串行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
    
        //创建串行队列
        dispatch_queue_t serialqueue = dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);//异步提交到串行队列
        dispatch_async(serialqueue, ^{
            NSLog(@"%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_async(serialqueue, ^{
            NSLog(@"%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
       [NSThread sleepForTimeInterval:
    2]; NSLog(@"main:%@",[NSThread currentThread]); }

    2014-10-31 15:39:06.242 IOS多线程[15238:1403] <NSThread: 0x8e39b60>{name = (null), num = 2}

    2014-10-31 15:39:08.243 IOS多线程[15238:90b] main:<NSThread: 0x8b4bf00>{name = (null), num = 1}

    2014-10-31 15:39:09.243 IOS多线程[15238:1403] <NSThread: 0x8e39b60>{name = (null), num = 2}

    分析:上面代码一共有两条队列,我们自己创建的串行队列以及主线程队列,异步提交dispatch_async会立即返回不会阻塞主线程后面的代码,所以两条队列异步执行,又因为serialqueue是串行队列,所以我们提交的任务依次执行。

     

    异步提交代码二:(主线程串行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        dispatch_queue_t mainqueue = dispatch_get_main_queue();
        //异步提交到串行队列
        dispatch_async(mainqueue, ^{
            NSLog(@"task1:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_async(mainqueue, ^{
            NSLog(@"task2:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"main:%@",[NSThread currentThread]);
        
    }

    2014-10-31 16:00:02.820 IOS多线程[15350:90b] main:<NSThread: 0x8b799c0>{name = (null), num = 1}

    2014-10-31 16:00:02.835 IOS多线程[15350:90b] task1:<NSThread: 0x8b799c0>{name = (null), num = 1}

    2014-10-31 16:00:05.837 IOS多线程[15350:90b] task2:<NSThread: 0x8b799c0>{name = (null), num = 1}

    分析:异步添加两个任务到主线程队列(串行队列),dispatch_async会立刻返回,主线程程序执行完后会依次执行添加到主线程队列的任务

     

    异步提交代码三(并行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        //创建并发队列
        dispatch_queue_t concurrentqueue = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
        
        
        //异步提交到串行队列
        dispatch_async(concurrentqueue, ^{
            NSLog(@"task1:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_async(concurrentqueue, ^{
            NSLog(@"task2:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"main:%@",[NSThread currentThread]);
    
    }

    2014-10-31 16:05:03.272 IOS多线程[15385:3607] task2:<NSThread: 0x8b76200>{name = (null), num = 3}

    2014-10-31 16:05:03.272 IOS多线程[15385:1403] task1:<NSThread: 0x8e29f00>{name = (null), num = 2}

    2014-10-31 16:05:05.273 IOS多线程[15385:90b] main:<NSThread: 0x8b3c2a0>{name = (null), num = 1}

    分析:上面创建了两个队列,异步提交dispatch_async立即返回不会阻塞主线程后面的代码,所以两个队列异步执行,又因为我们创建的队列是并行队列,所以我们提交到队列中的两个任务也会并行执行

     

    同步提交也有代码块和函数两种方式

    我们把任务同步提交给并行队列,主线程队列以及自定义队列时会有以下不同结果

    同步提交代码一:(自定义串行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        //创建串行队列
        dispatch_queue_t serialqueue = dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);
        
        //同步提交到串行队列
        dispatch_sync(serialqueue, ^{
            NSLog(@"task1:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_sync(serialqueue, ^{
            NSLog(@"task2:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"main:%@",[NSThread currentThread]);
    
    }

    2014-10-31 16:17:50.113 IOS多线程[15438:90b] task1:<NSThread: 0x8b7cfb0>{name = (null), num = 1}

    2014-10-31 16:17:53.114 IOS多线程[15438:90b] task2:<NSThread: 0x8b7cfb0>{name = (null), num = 1}

    2014-10-31 16:17:58.117 IOS多线程[15438:90b] main:<NSThread: 0x8b7cfb0>{name = (null), num = 1}

    分析:因为使用了同步提交dispatch_sync,该函数只有当提交的任务执行完才会返回继续执行后面的代码

     

    同步提交代码二:(主线程串行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        dispatch_queue_t mainqueue = dispatch_get_main_queue();
        
        //同步提交到串行队列
        dispatch_sync(mainqueue, ^{
            NSLog(@"task1:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_sync(mainqueue, ^{
            NSLog(@"task2:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"main:%@",[NSThread currentThread]);
    
    } 

    分析:以上代码是错误的会产生死锁,因为通过dispatch_sync提交任务会等执行完才返回,而任务又被提交到了主线程串行队列,所以会先等待主线程代码执行完,主线程又在等待dispatch_sync返回,两者相互等待对方执行,所以产生了死锁。

     

    同步提交代码三:(并行队列)

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        //创建并发队列
        dispatch_queue_t concurrentqueue = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
        
        
        //同步提交到串行队列
        dispatch_sync(concurrentqueue, ^{
            NSLog(@"task1:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        
        dispatch_sync(concurrentqueue, ^{
            NSLog(@"task2:%@",[NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        });
        
        [NSThread sleepForTimeInterval:2];
        NSLog(@"main:%@",[NSThread currentThread]);
    
    }

    2014-10-31 16:21:01.445 IOS多线程[15453:90b] task1:<NSThread: 0x8b769a0>{name = (null), num = 1}

    2014-10-31 16:21:04.447 IOS多线程[15453:90b] task2:<NSThread: 0x8b769a0>{name = (null), num = 1}

    2014-10-31 16:21:09.449 IOS多线程[15453:90b] main:<NSThread: 0x8b769a0>{name = (null), num = 1}

    分析:因为使用了同步提交dispatch_sync,该函数只有当提交的任务执行完才会返回继续执行后面的代码,所以当使用同步提交时,并行队列和自定义的串行队列作用是一样的

     

    GCD其他常用方法

     执行多个操作:dispatch_apply

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        //串行队列
        dispatch_queue_t serialqueue = dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);
        
        //主线程队列
        dispatch_queue_t mainqueue = dispatch_get_main_queue();
        
        //并发队列
        dispatch_queue_t concurrentqueue = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
    
        
        dispatch_apply(5, concurrentqueue, ^(size_t time) {
            NSLog(@"第%zu此执行,%@",time,[NSThread currentThread]);
        });
        
        NSLog(@"main");
    }

    输出

    2014-10-31 19:44:26.816 IOS多线程[15709:3a03] 3此执行,<NSThread: 0x9b68ce0>{name = (null), num = 4}

    2014-10-31 19:44:26.816 IOS多线程[15709:1403] 0此执行,<NSThread: 0x8b7a410>{name = (null), num = 2}

    2014-10-31 19:44:26.816 IOS多线程[15709:90b] 1此执行,<NSThread: 0x8b7a2d0>{name = (null), num = 1}

    2014-10-31 19:44:26.816 IOS多线程[15709:3903] 2此执行,<NSThread: 0x996a630>{name = (null), num = 3}

    2014-10-31 19:44:26.817 IOS多线程[15709:3a03] 4此执行,<NSThread: 0x9b68ce0>{name = (null), num = 4}

    2014-10-31 19:44:26.818 IOS多线程[15709:90b] main

    如果把dispatch_apply队列换成串行队列输出如下

    2014-10-31 19:52:07.125 IOS多线程[15724:90b] 0此执行,<NSThread: 0x8b28ad0>{name = (null), num = 1}

    2014-10-31 19:52:07.126 IOS多线程[15724:90b] 1此执行,<NSThread: 0x8b28ad0>{name = (null), num = 1}

    2014-10-31 19:52:07.126 IOS多线程[15724:90b] 2此执行,<NSThread: 0x8b28ad0>{name = (null), num = 1}

    2014-10-31 19:52:07.126 IOS多线程[15724:90b] 3此执行,<NSThread: 0x8b28ad0>{name = (null), num = 1}

    2014-10-31 19:52:07.127 IOS多线程[15724:90b] 4此执行,<NSThread: 0x8b28ad0>{name = (null), num = 1}

    2014-10-31 19:52:07.127 IOS多线程[15724:90b] main

    如果换成主线程队列则会产生死锁

     

    只执行一次任务(可以用来实现单例模式):

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        //执行代码块
    });

    onceToken用来判断代码块是否已经执行过,它的本质是一个long型整数

     

    指定时间点执行任务:

    dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block); 

     

    分组:

    如果希望队列中所有任务结束后执行某个操作(比如执行3个下载任务,全部完成后通知界面更新),那么可以使用分组

        //主线程队列
        dispatch_queue_t mainqueue = dispatch_get_main_queue();
        
        //并发队列
        dispatch_queue_t concurrentqueue = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
    
        
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, concurrentqueue, ^{
            NSLog(@"task1");
        });
        dispatch_group_async(group, concurrentqueue, ^{
            NSLog(@"task2");
        });
        dispatch_group_notify(group, mainqueue, ^{
            NSLog(@"updateui");
        });

    上面代码当task1和task2都执行完后才会执行notify中的任务

    分界:

    分界是指同一队列中当前面添加的任务执行完才会执行分界任务,而且只有当分界任务执行完才会执行后面添加的任务

        dispatch_queue_t concurrentqueue = dispatch_queue_create("concurrentqueue", DISPATCH_QUEUE_CONCURRENT);
    
        
        dispatch_async(concurrentqueue, ^{
            NSLog(@"task1");
        });
        
        dispatch_async(concurrentqueue, ^{
            NSLog(@"task2");
        });
        
        dispatch_barrier_async(concurrentqueue, ^{
            NSLog(@"barriertasck");
        });
        
        dispatch_async(concurrentqueue, ^{
            NSLog(@"lasttask");
        });

     上面代码只有当task1和task2执行完才会执行分解任务barriertask,当分解任务执行完才会执行lasttask

  • 相关阅读:
    W3C标准
    Oracle数据库中的几个名字及监听的配置问题
    Linux中特别要注意用户与文件权限的问题
    Linux中mv重命名作用及打包war压缩文件及分配权限
    虚拟机的ip网络设置的选择
    sqlplus中登陆账户用@加上数据库sid
    bat文件从@含义起
    我原来还在这
    Hibernate的数据操作(4.*以上版本)
    Hibernate中的配置文件
  • 原文地址:https://www.cnblogs.com/zanglitao/p/4065344.html
Copyright © 2011-2022 走看看