iOS开发网络多线程之多线程

iOS开发笔记-多线程01

理论部分:

一.进程

1)概念:是指在系统中正在运行的一个应用程序,每个进程的存储空间是独立的(终端中输入top可以查看进程,按Q退出)

P.S.进程与应用程序的差别:进程是有状态的,正在执行的

2)进程是CPU进行资源分配与调度的基本单位

二.线程

1)线程是CPU调度的基本单位(1个进程想执行任务,必须要有线程 ),一个进程中所有的任务都在线程中执行

2)一个线程中的任务的执行是串行的

P.S.进程与线程的辨析

1)一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程,线程是进程的一条路径

2)同一个进程内的线程共享进程的资源

3)进程可以分配资源,而线程不可以

3)多线程并发执行:其实是CPU快速地在多个线程之间调度(只是假象,因为同一时间,CPU只能处理一条线程),建议开辟线程数量为3-5条

4)主线程:也称为UI线程,作用是:1.显示\刷新UI界面 2.处理UI事件 (所有和UI相关的操作都需要在主线程中执行)

打印时,若显示的number等于1,则为主线程,其他数字,则为子线程

P.S.主线程注意点

1.不要将耗时的任务放在主线程

2.UI刷新操作要放在主线程中

3.耗时的操作放在子线程中(后台线程)

三.pthread


说明:pthread的基本使用(需要包含头文件)
    //使用pthread创建线程对象
    pthread_t thread;
    //使用pthread创建线程
    //第一个参数:线程对象地址
    //第二个参数:线程属性
    //第三个参数:指向函数的指针
    //第四个参数:传递给该函数的参数
    pthread_create(&thread, NULL, run, NULL);

四.NSThread

1.一个NSThread代表一条线程

2.优先级高,cpu调用的概率高(影响的也是CPU调度到的概率)


1)NSThread创建线程的四种方式
        //第一种创建线程的方式:alloc initWithTarget.
        //特点:需要手动开启线程,可以拿到线程对象进行详细设置
            //创建线程
            /*
             第一个参数:目标对象
             第二个参数:选择器,线程启动要调用哪个方法
             第三个参数:前面方法要接收的参数(最多只能接收一个参数,没有则传nil)
             */
            NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"hmx"];
             //启动线程
            [thread start];

        //第二种创建线程的方式:分离出一条子线程
        //特点:自动启动线程,无法对线程进行更详细的设置
            /*
             第一个参数:线程启动调用的方法
             第二个参数:目标对象
             第三个参数:传递给调用方法的参数
             */
            [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分离出来的子线程"];

        //第三种创建线程的方式:后台线程
        //特点:自动启动线程,无法进行更详细设置
            [self performSelectorInBackground:@selector(run:) withObject:@"我是后台线程"];
        
        //第四种创建线程方法:alloc init
        //新建一个类 继承自NSThread,重写内部的main方法来封装任务
            NSThread *thread = [[NSThread alloc]init];
            //启动线程
            [thread start];

    2)设置线程的属性
        //设置线程的名称
        thread.name = @"线程A";

        //设置线程的优先级,注意线程优先级的取值范围为0.0~1.0之间,1.0表示线程的优先级最高,如果不设置该值,那么理想状态下默认为0.5
        thread.threadPriority = 1.0;

3.线程状态相关问题:

1.线程的各种状态:新建-就绪-运行-阻塞-死亡
2.当线程的任务执行完毕之后就销毁了
3.当线程放入可调度线程池中,CPU才会调度
4.线程已经死了,是不能再重新打开的
5.当线程解除阻塞状态时,会进入就绪状态,而不是运行状态

4.线程安全相关问题:

    1. 互斥锁:@synchronized(self){//需要锁定的代码}(推荐使用self)
    2. 前提条件:多个线程可能会访问同一块资源
    3. 注意点:1)要注意加锁的位置
             2)锁对象必须是对象,且全局唯一
             3)加上互斥锁之后,就会使线程同步(即线程永远都是按一个顺序调用,例:一开始是2->1->3的顺序,之后依旧为2->1->3的顺序)
             4)线程是需要消耗性能的
    4. 专业术语-线程同步
    5. 原子和非原子属性(是否对setter方法加锁)
       atomic 线程安全,需要消耗大量资源
       nonatomic 非线程安全,适合内存小的移动设备  (开发中声明为这个)

5.计算代码段间的执行时间


        //第一种方法
            NSDate *start = [NSDate date];
            //2.根据url地址下载图片数据到本地(二进制数据)
            NSData *data = [NSData dataWithContentsOfURL:url];

            NSDate *end = [NSDate date];
            NSLog(@"第二步操作花费的时间为%f",[end timeIntervalSinceDate:start]);

        //第二种方法
            CFTimeInterval start = CFAbsoluteTimeGetCurrent();
            NSData *data = [NSData dataWithContentsOfURL:url];

            CFTimeInterval end = CFAbsoluteTimeGetCurrent();
            NSLog(@"第二步操作花费的时间为%f",end - start);

6.回到主线程刷新UI

    //4.1 第一种方式
        [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
    //4.2 第二种方式
        [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    //4.3 第三种方式
        [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
    }

五.PCD

1.GCD基本知识

1) 两个核心概念:队列和任务:
    队列:用来存放任务(决定在哪个线程执行任务)
    任务:执行什么操作
2) 同步函数和异步函数的区别:
    同步:1.只能在当前线程中执行,不具备开启新线程的能力
        2.执行任务的方式:当执行到我时必须等我执行完才能执行后面的任务
    异步:1.可以在新的线程中执行任务,具备开启新线程的能力
        2.执行任务的方式:可以不用等我执行完毕,就可以直接执行后面的任务
3)  串行队列:1.取出一个任务后,等到该任务执行完毕之后,接着去第二个任务
            2.创建方式:a.自己创建  b.主队列
    并行队列:1.取出一个任务后,接着执行第二个任务
            2.创建方式:a.自己创建  b.全局并发队列
    主队列:1.在安排任务的时候,会先检查主线程的状态,如果主线程忙,那么久暂停调度直到空闲为止
          2.想要实现控制系统开几条线程时,只需要控制创建几个队列
          3.凡是放在主队列里的任务都在主线程完成

2.GCD基本使用【重要】

01 异步函数+并发队列:开启多条线程,并发执行任务
02 异步函数+串行队列:开启一条线程,串行执行任务
03 同步函数+并发队列:不开线程,串行执行任务
04 同步函数+串行队列:不开线程,串行执行任务
05 异步函数+主队列:不开线程,在主线程中串行执行任务
06 同步函数+主队列:不开线程,串行执行任务(注意死锁发生)
   P.S若当前是子线程执行的同步函数加上主队列的方式,不会发生死锁
07 注意同步函数和异步函数在执行顺序上面的差异

3.GCD的线程间通信:


        //0.获取一个全局的队列
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

        //1.先开启一个线程,把下载图片的操作放在子线程中处理
        dispatch_async(queue, ^{

        //2.下载图片
            NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];

            NSLog(@"下载操作所在的线程--%@",[NSThread currentThread]);

        //3.回到主线程刷新UI
            dispatch_async(dispatch_get_main_queue(), ^{
               self.imageView.image = image;
               //打印查看当前线程
                NSLog(@"刷新UI---%@",[NSThread currentThread]);
            });

        });

4.GCD相关注意点

1. 开线程的两个条件:1.必须是异步函数 2.必须不是主队列(主线程)
2. 放到主队列里的任务,必须要在主线程中执行(不一定在当前线程中执行,即即使在子线程中调用了主队列,还是子主线程中调用)

5.GCD常用函数:

   
   1)栅栏函数(控制任务的执行顺序)
        dispatch_barrier_async(queue, ^{
            NSLog(@"--dispatch_barrier_async-");
        });
    /*
    P.S 注意点:1.栅栏函数可以控制线程的执行顺序
              2.栅栏函数不能使用全局并发队列
              3.栅栏函数在执行时是独占的
              4.dispatch_barrier_async == dispatch_async  这两个是等同的
    */
    
    2)延迟执行(延迟·控制在哪个线程执行)
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"---%@",[NSThread currentThread]);
        });
    /*
    Q:GCD的延迟执行 是先等2秒再提交 OR 先提交再等2秒?
    A:先等2秒再提交(延迟提交)  因为任务提交到队列里就不好控制了
    */

    3)一次性代码(注意不能放到懒加载)
        -(void)once
        {
            //整个程序运行过程中只会执行一次
            //onceToken用来记录该部分的代码是否被执行过
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{

                NSLog(@"-----");
            });
        }
    /*
    一次性代码的特点:1.整个程序运行过程中只会执行一次
                      2.它本身是线程安全的
    */

    4)快速迭代(开多个线程并发完成迭代操作)
           dispatch_apply(subpaths.count, queue, ^(size_t index) {
        });
     /*
     快速迭代:多个线程(子线程与主线程一起工作的)一起并发执行任务的--->对顺序没有要求时使用
     Q:快速迭代若不是从0开始,怎么处理
     A:初始值若不是0,则不需要使用GCD的快速迭代,使用for循环即可
     */
    
    5)队列组(同栅栏函数)--->调度组
        //创建队列组
        dispatch_group_t group = dispatch_group_create();
        //队列组中的任务执行完毕之后,执行该函数
        dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);//这个方法本身也是异步的

    /*
    方便管理一个组内的操作
    */

    6)进入群组和离开群组
        dispatch_group_enter(group);//执行该函数后,后面异步执行的block会被gruop监听
        dispatch_group_leave(group);//异步block中,所有的任务都执行完毕,最后离开群组
       /*
       注意:dispatch_group_enter|dispatch_group_leave必须成对使用
            当需要监听多个任务时,则重复写一组即可
       */
       //死等方法:知道队列组中所有都执行完毕之后才过掉该方法(同步)
       //diepatch_group_wait(group,DISPATCH_TIME_FOREVER)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • 从哪说起呢? 单纯讲多线程编程真的不知道从哪下嘴。。 不如我直接引用一个最简单的问题,以这个作为切入点好了 在ma...
    Mr_Baymax阅读 2,752评论 1 17
  • 什么是进程? 进程是指在系统中正在运行的一个应用程序。 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存...
    珍此良辰阅读 1,255评论 1 5
  • 欢迎大家指出文章中需要改正或者需要补充的地方,我会及时更新,非常感谢。 一. 多线程基础 1. 进程 进程是指在系...
    xx_cc阅读 7,184评论 11 70
  • 背景 担心了两周的我终于轮到去医院做胃镜检查了!去的时候我都想好了最坏的可能(胃癌),之前在网上查的症状都很相似。...
    Dely阅读 9,235评论 21 42
  • Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么? 1...
    AlanGe阅读 1,734评论 0 17