iOS_多线程理解

1.基本概念:

什么是进程:

1)进程是一个具有独立功能的程序关于某次数据集合的一次运行活动,他是操作系统分配资源的基本单元.

2) 进程是指在系统中正在运行的一个应用程序,就是一段程序执行的过程,我们可以理解为手机上的一个app

3)每个进程之间是独立的,每个进程均运行在专用且受保护的内存空间内,拥有独立运行,所需的全部资源

什么是线程

1)程序执行流的最小单元,线程是进程中的一个实体

2)一个进程要想执行任务,必须要至少有一条线程,应用启动的时候,系统会默认开启一条线程,也就是主线程;

线程和进程之间的关系

1)线程是进程的基本执行单位,进程的所有任务必须在线程中执行(主线程,子线程)

2)线程是cpu分配资源的最小单元,一个进程中所有线程共享进程资源

3)一个进程对应多个或者一个线程,但是必须要有线程

队列:这里的队列是指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用FIFO的原则,即新任务是被插入到队列末尾,读取总是从头部开始读取,读取一个释放一个

在GCD中有两种队列,串行和并发,遵循FIFO 区别在于自行顺序不同,开启线程数不同

iOS 中的多线程

NSThread,NSoperationQueue,GCD

我们要明确 NSOperationQueue 与 GCD 之间的关系

GCD 是面向底层的 C 语言的 API,NSOpertaionQueue 用 GCD 构建封装的,是 GCD 的高级抽象。

1、GCD 执行效率更高,而且由于队列中执行的是由 block 构成的任务,这是一个轻量级的数据结构,写起 来更方便

2、GCD 只支持 FIFO 的队列,而 NSOperationQueue 可以通过设置最大并发数,设置优先级,添加依赖关系 等调整执行顺序

3、NSOperationQueue 甚至可以跨队列设置依赖关系,但是 GCD 只能通过设置串行队列,或者在队列内添 加 barrier(dispatch_barrier_async)任务,才能控制执行顺序,较为复杂

4、NSOperationQueue 因为面向对象,所以支持 KVO,可以监测 operation 是否正在执行(isExecuted)、 是否结束(isFinished)、是否取消(isCanceld)

  实际项目开发中,很多时候只是会用到异步操作,不会有特别复杂的线程关系管理,所以苹果推崇的 且优化完善、运行快速的 GCD 是首选

  如果考虑异步操作之间的事务性,顺序行,依赖关系,比如多线程并发下载,GCD需要自己写更多的 代码来实现,而 NSOperationQueue 已经内建了这些支持

  不论是GCD还是NSOperationQueue,我们接触的都是任务和队列,都没有直接接触到线程,事实上 线程管理也的确不需要我们操心,系统对于线程的创建,调度管理和释放都做得很好。而 NSThread 需要我们自己去管理线程的生命周期,还要考虑线程同步、加锁问题,造成一些性能上的开销


2、performSelector

dispatch_async(dispatch_get_global_queue(0, 0), ^{

        [self performSelector:@selector(threadFucntion) withObject:nil afterDelay:0];

    });

这里的 threadFucntion 方法是不会去执行的,原因在于

这个方法要创建提交任务到 runloop 上的,而 gcd 底层创建的线程是默认没有开启对应 runloop 的,所有 这个方法就会失效。

而如果将 dispatch_get_global_queue 改成主队列,由于主队列所在的主线程是默认开启了 runloop 的, 就会去执行(将 dispatch_async 改成同步,因为同步是在当前线程执行,那么如果当前线程是主线程,test 方法也是会去执行的)。

1、问:怎么用 GCD 实现多读单写?

多读单写的意思就是:可以多个读者同时读取数据,而在读的时候,不能去写入数据。并且,在写的过程 中,不能有其他写者去写。即读者之间是并发的,写者与读者或其他写者是互斥的。

这里的写处理就是通过栅栏的形式去写。 就可以用 dispatch_barrier_sync(栅栏函数)去实现

多读单写实现方式:

-(id)readDataForKey:(NSString*)key{

    __blockidresult;


    //当前线程和取的线程为同一个

    dispatch_queue_t concurrent = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);


    dispatch_sync(concurrent, ^{

        result = [selfvalueForKey:key];

    });

    returnresult;

}

-(void)writeDataForKey:(NSString*)key{


    dispatch_queue_t concurretn = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);


    dispatch_barrier_async(concurretn, ^{

        [selfsetValue:@"data"forKey:key];

    });

}

介绍:dispatch_group_async

场景:在 n 个耗时并发任务都完成后,再去执行接下来的任务。比如,在 n 个网络请求完成后去刷新 UI 页 面。

dispatch_queue_t concurrentQueen = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

    dispatch_group_t group = dispatch_group_create();

    for(NSIntegeri =0; i <5; i ++ ) {

        dispatch_group_async(group, concurret, ^{

            sleep(1);

            NSLog(@"网络请求 %ld",i);

        });

    }

    dispatch_group_notify(group,concurrentQueen, ^{

        NSLog(@"刷新页面");

    });

介绍:Dispatch Semaphore

GCD 中的信号量是指 Dispatch Semaphore,是持有计数的信号。

A 常用做,保持线程同步,将异步执行任务转换为同步执行

B 保持线程安全,为线程加锁

__blockNSIntegernumber =0;

    dispatch_semaphore_t semphone = dispatch_semaphore_create(0);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        number =100;

        sleep(10);

        dispatch_semaphore_signal(semphone);

    });

    dispatch_semaphore_wait(semphone, DISPATCH_TIME_FOREVER);


    NSLog(@"321321aaaaaaa13231  %ld",number);

发现 过了10秒钟才打印number = 10 ;

说明阻塞了当前线程,将异步执行,转换为同步了

在线程安全中可以将 dispatch_semaphore_wait 看作加锁,而 dispatch_semaphore_signal 看作解锁 首先创建全局变量

@property (nonatomic,strong)dispatch_semaphore_t semphore;

//为线程加锁

-(void)semPhoreLock{

    dispatch_semaphore_wait(_semphore, DISPATCH_TIME_FOREVER);

    _count++ ;

    sleep(1);

    NSLog(@"sdad  d3232 %d",_count);

    dispatch_semaphore_signal(_semphore);

}

-(void)asyncDic{

    _semphore = dispatch_semaphore_create(1);

    for(inti =0; i <100; i ++ ) {

        dispatch_async(dispatch_get_global_queue(0, 0), ^{

            [selfsemPhoreLock];

        });

    }

}

观察到打印是从1打印100,且dispatch_semaphore_t必须用strong修饰

原因如下:

在子线程中并发执行 asyncTask,那么第一个添加到并发队列里的,会将信号量减 1,此时信号量等于 0, 可以执行接下来的任务。而并发队列中其他任务,由于此时信号量不等于 0,必须等当前正在执行的任务 执行完毕后调用 dispatch_semaphore_signal 将信号量加 1,才可以继续执行接下来的任务,以此类推,从而 达到线程加锁的目的。

延时函数

dispatch_after 

dispatch_after 能让我们添加进队列的任务延时执行,该函数并不是在指定时间后执行处理,而只是在指 定时间追加处理到 dispatch_queue

dispatch_once_tonce 实现单例

-(instancetype)shareInstance{

    static dispatch_once_tonceToken;

    static id instance =nil;

    dispatch_once(&onceToken, ^{

        instance = [[self alloc]init];

    });

    return instance;

}

NSThread+runloop 实现常驻线程


[self performSelector:@selector(threadJJJ) onThread:[ViewController shareThread] withObject:nil waitUntilDone:NO];

调用performselector 这个就实现了打印,说明,实现NSThread + RunRoop 实现成功了

自旋锁:是一种用于保护多线程共享资源的锁,与一般互斥锁(mutex)不同之处在于当自旋锁尝试获取锁时以忙等 待(busy waiting)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住), 那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。在多 CPU 的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。

互斥锁:当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕, 当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务。

自旋锁会忙等: 所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是不停循环在那里,直到被锁 资源释放锁。互斥锁会休眠: 所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时 cpu 可以调度其他线程工 作。直到被锁资源释放锁。此时会唤醒休眠线程。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容