多线程(GCD)

多线程(GCD)

GCD的基本使用

  • GCD是苹果为多核并行运算提出的解决方案
  • GCD会自动利用更多的内核
  • GCD同NSOperation一样,也会自动管理线程的生命周期
  • GCD是C的代码,较NSOperation性能更高
  • GCD也是以队列的形式工作,FIFO
  • 基本用法
    //线程间通信
    //进入子线程进行耗时操作
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%@",[NSThread currentThread]);
        //回主线程进行刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"%@",[NSThread currentThread]);
        });
    });

GCD的两种队列

  • 并发队列(ConcurrentQueue):可以并发执行多个任务,允许开启多个线程同时执行任务(只是允许,要根据是否具有开启新线程的能力),所以只有异步函数才会对并发队列起作用,
  • 串行队列(SerialQueue):让任务一个接着一个的执行,
    • GCD自带一个特殊的串行队列为主队列,主队列自动会放到主线程中执行
    • GCD还自带一个全局的并发队列,可以设置优先级(dispatch_get_global_queue)

同步和异步

  • 同步:只能在当前线程中执行任务,不具备开启新线程的能力
  • 异步:具备开启新线程的能力
同步 异步
串行 没有开启线程,串行执行任务 开启一条线程,串行执行任务
并发 没有开启线程,串行执行任务 开启线程(大于等于1条,不受控制),并发执行任务

各种函数队列演示代码

同步串行(打印结果12345)

//创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create("duilie", DISPATCH_QUEUE_SERIAL);
//创建一个并行队列
    dispatch_queue_t queeu = dispatch_queue_create("bbb", DISPATCH_QUEUE_CONCURRENT);
    //同步执行这个串行队列(顺序执行,不会创建新的线程)
    dispatch_sync(queue, ^{
        NSLog(@"1%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"4%@",[NSThread currentThread]);
    });
    NSLog(@"5%@",[NSThread currentThread]);

同步并行(打印结果12345)

    //同步执行一个并行队列(顺序执行,没有开启线程,只是允许并行执行,但是没有线程这个条件,实际还是串行执行)
    dispatch_sync(queeu, ^{
        NSLog(@"1%@",[NSThread currentThread]);
    });
    dispatch_sync(queeu, ^{
        NSLog(@"2%@",[NSThread currentThread]);
    });
    dispatch_sync(queeu, ^{
        NSLog(@"3%@",[NSThread currentThread]);
    });
    dispatch_sync(queeu, ^{
        NSLog(@"4%@",[NSThread currentThread]);
    });
    NSLog(@"5%@",[NSThread currentThread]);

异步串行(打印结果1234,5不一定插在1234的哪个位置,因为1234和5是并行的,1234是串行的)

    //异步执行这个串行队列(1234顺序执行,5和1234并行,开启一条线程,)
    dispatch_async(queue, ^{
        NSLog(@"1%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"4%@",[NSThread currentThread]);
    });
    NSLog(@"5%@",[NSThread currentThread]);

异步并行(打印结果随机,12345五个任务执行都是并发)

    //异步执行一个并行队列(主线程和其他线程一起执行,顺序不一定,开启的线程数也不一定)
    dispatch_async(queeu, ^{
        NSLog(@"1%@",[NSThread currentThread]);
    });
    dispatch_async(queeu, ^{
        NSLog(@"2%@",[NSThread currentThread]);
    });
    dispatch_async(queeu, ^{
        NSLog(@"3%@",[NSThread currentThread]);
    });
    dispatch_async(queeu, ^{
        NSLog(@"4%@",[NSThread currentThread]);
    });
    NSLog(@"5%@",[NSThread currentThread]);

系统提供的五种队列(1主队列 + 4全局子队列)

    //1.当前队列的优先级2.没用
    /**
     * DISPATCH_QUEUE_PRIORITY_HIGH 2
     * DISPATCH_QUEUE_PRIORITY_DEFAULT 0
     * DISPATCH_QUEUE_PRIORITY_LOW (-2)
     * DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
     */
    //获取到全局子队列
    dispatch_queue_t qq = dispatch_get_global_queue(0, 0);
    //获取主队列
    dispatch_queue_t q =  dispatch_get_main_queue();

GCD的其他函数

  • 延时执行
 //延时执行
    //参数:几秒后执行(填的是2,代表两秒后执行)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延迟执行的代码片段");
    });
    NSLog(@"我先走了");
  • 只执行一次(线程安全,只有创建单例用它,其他地方不要用)
    //只执行一次(线程安全的)
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只走一次");
    });
  • 重复执行
 //重复执行
    //1.重复的次数 2.在什么队列重复 3.当前次数的索引
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t a) {
        NSLog(@"%zu",a);
    }) ;
  • 线程组
    • 本质是先把任务放到队列中,再把队列放入组内
    • 优点:可以监听组内的任务完毕
//创建一个组(先把任务放进队列里,在放进组里,组可以监听任务完毕)
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任务1");
    });
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任务2");
    });
    //监听组内执行情况(监听组内所有队列执行完毕)
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行完毕");
    });
  • 单独执行(dispatch_barrier_async)
    • 本质是在并发队列中拥有串行的权利
    • 如果有12345个任务,给3任务设置单独执行,按照12345的顺序添加任务,那么一定是12执行完才会执行3,3执行完才会执行45,所以12和45在执行的时候是并发,但是到了3,12和3和45其实是串行的
    • 注意:如果想要这样设置其执行顺序(其实是仿照NSOperation设置依赖),那么所在的队列一定不能是系统提供的全局并发队列
    //创建并发队列
    dispatch_queue_t tt = dispatch_queue_create("tt", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(tt, ^{
        NSLog(@"任务1");
    });
    dispatch_async(tt, ^{
        NSLog(@"任务2");
    });
    //单独执行
    dispatch_barrier_sync(tt, ^{
        NSLog(@"任务3");
    });
    dispatch_async(tt, ^{
        NSLog(@"任务4");
    });
    dispatch_async(tt, ^{
        NSLog(@"任务5");
    });
  • block变成函数执行
    • 本质是将block块变成c语言的函数,两种方式是一样的(dispatch_async和dispatch_async_f)
 dispatch_async_f(dispatch_get_global_queue(0, 0), @"1", sum);
- void sum (void *a)
{
    NSLog(@"%@",a);
}

资源抢夺

  • 再实际开发过程中会将常出现卖票效应,其实就是多个线程访问同一个实例变量,并改变实例变量的值,就会导致实例变量的值发生错误,
  • 互斥锁(@synchronized)有效的解决了这个问题
  • 互斥锁原理:使用了线程同步技术,多条线程在同一条线上执行,并且按顺序执行
  • 将要访问的实例变量套用在互斥锁里面
    int a = 1000;
    //资源抢夺(对象)
    //互斥锁带的参数一定要传一个对象,一般情况传self
    @synchronized(self) {
        //锁的是代码
        a = a - 1;
    }
  • 互斥锁的缺点:会消耗大量的CPU资源
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容

  • #import "ViewController.h" @interface ViewController () @...
    艾克12138阅读 214评论 0 0
  • 目录 一、基本概念1.多线程2.串行和并行, 并发3.队列与任务4.同步与异步5.线程状态6.多线程方案 二、GC...
    BohrIsLay阅读 1,580评论 5 12
  • 最近颇花了一番功夫把多线程GCD人的一些用法总结出来,一来帮自己巩固一下知识、二来希望能帮到对这一块还迷茫...
    人活一世阅读 289评论 1 1
  • 一、简介在iOS所有实现多线程的方案中,GCD应该是最有魅力的,因为GCD本身是苹果公司为多核的并行运算提出的解决...
    MYS_iOS_8801阅读 571评论 0 0
  • 2017年10月21日,我与简书相遇了。 因为偶然间在某知名自媒体人的简历里看到她是一名简书签约作者,于是抱着好奇...
    伊文说阅读 1,418评论 37 22