iOS 多线程基础学习

1252638-9184f4909ab2f2d1.png

1.基本概念

  • 进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动。可以理解成一个运行中的应用程序。

  • 线程: 程序执行流的最小单元,线程是进程中的一个实体。

  • 同步: 只能在当前线程按先后顺序依次执行,不开启新线程。

  • 异步: 可以在当前线程开启多个新线程执行,可不按顺序执行

  • 队列: 装载线程任务的队形结构。

  • 并发: 线程执行可以同时一起进行执行。

  • 串行: 线程执行只能依次逐一先后有序的执行。

  • 一个进程可以有多个线程,也可以有多个队列

2.iOS多线程对比

  1. NSThread
    每个NSThread对象对应一个线程,真正最原始的线程。
    1)优点:NSThread 轻量级最低,相对简单。
    2)缺点:手动管理所有的线程活动,如生命周期、线程同步、睡眠等。

  2. NSOperation
    自带线程管理的抽象类。
    1)优点:自带线程周期管理,操作上可更注重自己逻辑。
    2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

  3. GCD
    Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
    1)优点:最高效,避开并发陷阱。
    2)缺点:基于C实现。

  4. 选择小结
    1)简单而安全的选择NSOperation实现多线程即可。
    2)处理大量并发数据,又追求性能效率的选择GCD。
    3)NSThread本人选择基本上是在做些小测试上使用,当然也可以基于此造个轮子。

3.场景选择

图片异步加载
这种常见的场景是最常见也是必不可少的。异步加载图片有分成两种来说明一下。

  • 第一种,在UI主线程开启新线程按顺序加载图片,加载完成刷新UI。
  • 第二种,依然是在主线程开启新线程,顺序不定地加载图片,加载完成个字刷新UI。

创作工具上的异步
这个跟上边任务调度道理差不多,只是为了丰富描述,有助于“举一反三”效果。如下描述的是app创作小说。

  • 场景一,app本地创作10个章节内容未成同步服务器,接着同时发表这10个章节将产生的一系列动作,其中上传内容,获取分配章节Id,如果后台没有做处理最好方式做异步按顺序执行。
  • 场景二,app本地创作列表中有3本小说要发表,如果同时发表创作列表中的3本小说,自然考虑并行队列执行发表。

4.使用方法

NSThread的使用
- (void)dynamicCreateThread
{
    //创建NSThread 动态
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
    thread.threadPriority = 1;
    [thread start];
}
- (void)staticCreateThread
{
    //创建静态线程
    [NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
    
}
- (void)implicitCreateThread
{
    //隐式创建线程
    [self performSelectorInBackground:@selector(loadImage) withObject:self];
}

NSThread的拓展认识
①获取当前线程

NSThread *current = [NSThread currentThread];

②获取主线程

NSThread *main = [NSThread mainThread];

③暂停当前线程

[NSThread sleepForTimeInterval:2];

④线程之间通信

//在指定线程上执行操作
[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES]; 
//在主线程上执行操作
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES]; 
//在当前线程执行操作
[self performSelector:@selector(run) withObject:nil];
NSOperation

主要的实现方式:结合NSOperation和NSOperationQueue实现多线程编程。
实例化NSOperation的子类,绑定执行的操作。
创建NSOperationQueue队列,将NSOperation实例添加进来。
系统会自动将NSOperationQueue队列中检测取出和执行NSOperation的操作。

使用NSOperation的子类实现创作线程。
①.NSInvocationOperation创建线程。

NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageSource:) object:imgUrl];
//[invocationOperation start];//直接会在当前线程主线程执行
NSOperationQueue *queue = [[NSOperationQueue alloc]init];[queue addOperation:invocationOperation];

②.NSBlockOperation创建线程

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 
       [self loadImageSource:imgUrl];
}];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:blockOperation];

GCD?

Grand Central Dispatch (GCD) 是 Apple 开发的一个多核编程的解决方法,GCD 是一个替代诸如 NSThread, NSOperationQueue, NSInvocationOperation 等技术的很高效和强大的技术。

分发队列种类(dispatch queue)
①.UI主线程队列 main queue

dispatch_get_main_queue()

②.并行队列global dispatch queue

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

这里的两个参数得说明一下:第一个参数用于指定优先级,分别使用DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW两个常量来获取高和低优先级的两个queue;第二个参数目前未使用到,默认0即可

③.串行队列serial queues

dispatch_queue_create("minggo.app.com", NULL);

6种多线程实现
①后台执行线程创建

dispatch_async(dispatch_get_global_queue(0, 0), ^{
 [self loadImageSource:imgUrl1];
});

②UI线程执行(只是为了测试,长时间加载内容不放在主线程)

dispatch_async(dispatch_get_main_queue(), ^{ 
[self loadImageSource:imgUrl1];
});

③一次性执行(常用来写单例)

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
 [self loadImageSource:imgUrl1];
});

④并发地执行循环迭代

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 size_t count = 10;
 dispatch_apply(count, queue, ^(size_t i) { 
 NSLog(@"循环执行第%li次",i);
 [self loadImageSource:imgUrl1];
});

⑤延迟执行

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
[self loadImageSource:imgUrl1];
});

⑥自定义dispatch_queue_t

dispatch_queue_t urls_queue = dispatch_queue_create("minggo.app.com", NULL);
dispatch_async(urls_queue, ^{ 
[self loadImageSource:imgUrl1];
});

对比多任务执行
异步加载图片是大部分app都要面对的问题,那么加载图片是按循序加载完之后才刷新UI呢?还是不安顺序加载UI呢?显然大部分的希望各自加载各自的图片,各自刷新。以下就是模拟这两种场景。
①先后执行,加载两张图片为例

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
   UIImage *image1 = [self loadImage:imgUrl1]; 
   UIImage *image2 = [self loadImage:imgUrl2]; 

   dispatch_async(dispatch_get_main_queue(), ^{ 
     self.imageview1.image = image1; 
     self.imageView2.image = image2; 

     });
});

②并行队列执行,也是以加载两张图片为例

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   dispatch_async(queue, ^{ dispatch_group_t group = dispatch_group_create();
   __block UIImage *image1 = nil; 
   __block UIImage *image2 = nil;

 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        image1 = [self loadImage:imgUrl1];
 }); 

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        image2 = [self loadImage:imgUrl2];
 }); 

dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
      self.imageview1.image = image1; 
      self.imageView2.image = image2; 
   });

});

①中等到两张图片加载完成后一起刷新,②就是典型的异步并行的例子,不需要理会各自图片加载的先后问题,完成加载图片刷新UI即可。从加载图片中来说,第①种不太合适使用,但是对于在上边场景选择中的创作工具来说有很大的好处,首先得异步进行,然后异步中有得按顺序执行几个任务,比如上传章节内容。因此,我们可以灵活考虑使用这两多线程任务执行方式,实现各种场景。

原文地址:http://www.jianshu.com/p/6e6f4e005a0b

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

推荐阅读更多精彩内容

  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 795评论 0 3
  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎样m阅读 1,266评论 0 1
  • .一.进程 进程:是指在系统中正在运行的一个应用程序,每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空...
    IIronMan阅读 4,479评论 1 33
  • 推酷诚意满满的技术周刊《编程狂人》第一七七期来了, 下面是内容列表,干货多多,也可以移步到官网进一步阅读。 前端开...
    推酷阅读 653评论 0 1
  • 时隔几天 再来简书 写点东西 一切真的已经物是人非了~人家说放不下一个人的时候 想想他是怎么放下你的 可能你也就放了
    净土ing阅读 204评论 0 0