iOS多线程-全面总结

iOS多线程-全面总结


  • 进程和线程

进程:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础(百度百科)

根据百度百科的解释我们知道进程是系统进行资源分配和调度的基本单位,在手机端一个进程就是一个app

线程:

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。(百度百科)

根据百度百科我们知道,线程来说其实是进程一个实体

一个进程中至少有一条线程,这条线程我们称为主线程

  • iOS中的创建线程和操作线程
  • pThread:纯c语言编写,需要自己管理线程的声明周期

OS X and iOS provide C-based support for creating threads using the POSIX thread API. This technology can actually be used in any type of application (including Cocoa and Cocoa Touch applications) and might be more convenient if you are writing your software for multiple platforms. The POSIX routine you use to create threads is called, appropriately enough, pthread_create.(苹果官方文档)

官方文档上说,这是一个基于C语言的创建和使用线程的API,而且是一个跨平台的API。查看官方文档https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW12

  • NSThread:OC封装面向对象,需要自己管理线程释放,相对用起来比较简单
四种创建方式:
// 1.需要调用start,才会去创建线程加入到当前队列
NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];

// 2.iOS10新加入的方法,同上
 NSThread *thread = [[NSThread alloc] initWithBlock:^{

    }];
 [myThread start];  // Actually create the thread
 // 3.detach 直接创建线程,加入当前队列
 [NSThread detachNewThreadWithBlock:^{
        [self task];
    }]; //@available iOS10
  // 4.同上
  [NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];

还有一些实用的熟悉和方法比如
currentThread、isMultiThreaded、
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
+ (void)exit; 等等如果查看NSThread.h文件

pThread、NSThread 都需要我们自己去创建管理线程的声明周期,所以之后出现了不要我们管理线程的生命周期的 GCD、NSOpration。


  • GCD:API基于C语言, 我们需要关心的概念是队列、任务,不在需要管理线程问题,CGD自动创建、分配、管理线程。

下面我们通过具体的代码例子,引出结论和理解:

  1. 同步队列
    NSLog(@"当前线程:%@", [NSThread currentThread]);
    
    dispatch_queue_t testQueue = dispatch_queue_create("com.haoyuhong.testQueue", NULL);
    
    /// 同步执行, 当前主线程串行执行
    dispatch_sync(testQueue, ^{
        NSLog(@"2. 当前线程: %@", [NSThread currentThread]);
    });
    
    /// 异步执行, 分配新线程执行
    dispatch_async(testQueue, ^{
        NSLog(@"3. 当前线程: %@", [NSThread currentThread]);
    });
    
    /// 异步执行,在已经分配的线程串行执行
    dispatch_async(testQueue, ^{
        NSLog(@"4. 当前线程: %@", [NSThread currentThread]);
    });
 
输出结果
当前线程:<NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125511+0800 TestGCD[95991:16450263] 2. 当前线程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125671+0800 TestGCD[95991:16450326] 3. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.125765+0800 TestGCD[95991:16450326] 4. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
我们得出以下结论:
* 串行队列总结: 串行队列,特点:保证顺序执行。
1. 如若同步执行,不分配线程,在当前线程串行执行;
2. 如若,异步执行,不阻塞当前线程,如果没有开辟新线程则开辟新线程,如果已经开辟了一条线程,则任务会在开辟的线程中串行执行,保持顺序执行。
死锁: 造成死锁的原因就是:相互等待,串行队列的特点就是顺序执行,如果同步执行任务在当前串行队列中执行,就会造成死锁。
  1. 并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.haoyuhong.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    
    /// 并发队列,同步任务,不分配线程,在当前线程执行
    dispatch_sync(concurrentQueue, ^{
       NSLog(@"1. 当前线程: %@", [NSThread currentThread]);
    });
    
    /// 并发队列,异步任务,分配线程,并发执行
    dispatch_async(concurrentQueue, ^{
        NSLog(@"2. 当前线程: %@", [NSThread currentThread]);
    });
    
    /// 并发队列,异步任务,分配线程,并发执行
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3. 当前线程: %@", [NSThread currentThread]);
    });
## 输出结果
2019-09-03 15:50:48.126185+0800 TestGCD[95991:16450263] 1. 当前线程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.126313+0800 TestGCD[95991:16450326] 2. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.126345+0800 TestGCD[95991:16450325] 3. 当前线程: <NSThread: 0x6000028d1b80>{number = 5, name = (null)}
总结如下
并发队列, 特点:并发执行
1. 同步任务,队列不会分配新线程去执行,在当前线程串行执行
2. 异步任务,队列分配新线程,所有异步任务,并发执行
  • 系统队列:

    1. 主队列
      串行队列,不管是同步还是异步,都不会创建新线程,所有任务都是在主线程执行,所以他是一种特殊的串行队列。如果当前执行线程为主线程,添加同步任务会造成,互相等待状态,导致死锁;异步执行,等待主线程此异步任务之前所有任务执行完毕执行。
      获取函数:dispatch_get_main_queue()
    2. 全局队列
      并发队列。
      获取函数:dispatch_get_global_queue(0, 0)
      第一个参数,服务质量决定任务执行的优先级
      The quality of service you want to give to tasks executed using this queue. Quality-of-service helps determine the priority given to tasks executed by the queue.QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_USER_INITIATED, QOS_CLASS_UTILITY, or QOS_CLASS_BACKGROUND
  • DispatchGroup
    dispatch_group: 将队列添加到队列组里
    队列组可以添加一个任务到队列并且将队列加入队列组

    • dispatch_group_create() /// 创建分发组

    • dispatch_group_async(dispatch_group_t group,
      dispatch_queue_t queue,
      dispatch_block_t block); /// 添加block任务到队列,并且关联到分发组

    • void
      dispatch_group_notify(dispatch_group_t group,
      dispatch_queue_t queue,
      dispatch_block_t block); /// 监听所有队列里的任务都完成后执行block里的任务

    • dispatch_group_wait(group, DISPATCH_TIME_FOREVER); /// 同步等待所有之前加入的任务都执行完毕

  • 栅栏函数
    栅栏函数:保证之前加入的任务都执行完毕,之后加入的任务等待栅栏任务执行完毕。

    • dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
    • void
      dispatch_barrier_sync(dispatch_queue_t queue,
      DISPATCH_NOESCAPE dispatch_block_t block);
      void
  • 延迟执行:

    • dispatch_after(dispatch_time_t when,
      dispatch_queue_t queue,
      dispatch_block_t block);
  • 执行一次函数:应用于单利的创建

    • dispatch_once(dispatch_once_t *predicate,
      DISPATCH_NOESCAPE dispatch_block_t block);

  • NSOperation
    NSOperation 是一个抽象任务类,不能直接使用,需要实例化两个子类使用,基于GCD的封装,将多线程简单化为队列和任务,使用起来也是很简单的
    *它与CGD的区别就是GCD是更底层的封装,在性能上会比NSOperation好点

    • NSBlockOperation:用一个block的方式初始化一个任务
      实例化:
      NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@”1-%@”, [NSThread currentThread]);
      }];

    • NSInvocationOperation:Target-Action的方式初始一个任务
      初始化方式:
      NSInvocationOperation *task2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];

    • NSOperationQueue :任务运行队列
      init方式初始:初始化一个并行队列
      NSOperationQueue *queue = [[NSOperationQueue alloc] init];
      mianQueue方式获取主队列:获取主队列,是一个串行队列
      NSOperationQueue *queue = [NSOperationQueue mainQueue];

      • 直接添加任务block到队列
        – (void)addOperationWithBlock:(void (^)(void))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
      • 设置并发数:maxConcurrentOperationCount
      • 挂起当前队列:suspended
      • 设置队列的优先级:qualityOfService
      • 取消队列所有任务: cancelAllOperations
      • 等待所有队列任务执行完成:
        – (void)waitUntilAllOperationsAreFinished;
    • 添加任务依赖:一个任务需要依赖另外一个任务执行完成才能执行
      – (void)addDependency:(NSOperation *)op;
      *移除依赖关系:
      – (void)removeDependency:(NSOperation *)op;

以上iOS多线程中知识,在此做一个总结,一起共勉!

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

推荐阅读更多精彩内容

  • 背景 担心了两周的我终于轮到去医院做胃镜检查了!去的时候我都想好了最坏的可能(胃癌),之前在网上查的症状都很相似。...
    Dely阅读 9,226评论 21 42
  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 789评论 0 3
  • 欢迎大家指出文章中需要改正或者需要补充的地方,我会及时更新,非常感谢。 一. 多线程基础 1. 进程 进程是指在系...
    xx_cc阅读 7,171评论 11 70
  • GCD (Grand Central Dispatch) :iOS4 开始引入,使用更加方便,程序员只需要将任务添...
    池鹏程阅读 1,323评论 0 2
  • RN 第三方库快速查找网址:https://js.coach/ (下面的文章以https://github.com...
    Tmac50阅读 16,772评论 3 10