iOS开发之多线程总结

最近面试遇到多线程各个实现方法的不同点,故学习整理了下,记录下笔记。
学习阶段,如果哪部分有问题,欢迎指正,共同探讨。@Apach3


一.多线程

(1)基本概念

1.进程:
在系统中正在运行的一个应用程序,每个进程之间是相互独立的,每个进程均运行在其专用且受保护的内存空间内。
2.线程:
一个进程(程序)的所有任务都在线程中执行,每个进程都至少有一个线程(主线程)。
3.多线程:
1个进程中可以开辟多条线程,多条线程可以并行(同时)执行不同的任务,多线程并发(同时)执行,其实是CPU快速的在多条线程之间切换。
4.主线程:
一个iOS程序运行后,默认会开启一条线程,称为“主线程”或“UI线程[处理UI事件(点击事件、滚动事件、拖拽事件等)、显示/刷新UI界面]”

(2)实现方案

1.pthread(C):
i.适用于Linux、Unix、Windows等系统;
ii.跨平台、可移植;
iii.一套通用的多线程API;
iiii.线程生命周期需程序员管理

2.NSThread(OC):
i.使用更加面向对象;
ii.可直接操作线程对象;
iii.线程生命周期需程序员管理

3.GCD(C):
i.充分利用设备的多核;
ii.线程生命周期自动管理

4.NSOperation(OC):
i.基于GCD(底层是GCD);
ii.使用更加面向对象;
iii.线程生命周期自动管理

(3)多线程优缺点

1.优点:
i.能适当提高程序的执行效率;
ii.能适当提高资源利用率(CPU、内存利用率)。

2.缺点:
i.创建线程是有开销的,iOS下主要包括以下成本:内核数据结构(大约1KB),栈空间,创建时间90毫秒;
ii.如果开启大量的线程,会降低程序的性能;
iii.线程越多,CPU在调度线程上的开销就越大;
iiii.程序设计更加复杂:比如线程之间的通信、多线程的数据共享。


二.NSThread

(1)一个NSThread对象就代表一条线程

(2)常见方法

1.创建、启动线程:

 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
 [thread start];

2.主线程:
i.获得主线程:+ (NSThread *)mainThread;
ii.是否为主线程:- (BOOL)isMainThread;

3.获得当前线程:

NSThread *current = [NSThread currentThread];

4.自定义子类继承NSOperation:
i.重写- (void)main;方法,在里面实现想执行的任务;
ii.自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池);
iii.经常通过- (BOOL)isCancelled;方法检测操作是否被取消,对取消做出相应。

(3)其他创建方式

1.创建线程后自动启动线程:

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

2.隐式创建并启动线程:

[self performSelectorInBackground:@selector(run) withObject:nil];

(4)线程状态

1.新建New:
进入就绪状态->运行状态。当线程任务执行完毕,自动进入死亡状态——>- (void)start;

2.就绪Runnable

3.强制停止线程

4.运行Running

5.阻塞Blocked:
i.

+ (void)sleepUntilDate:(NSDate *)date;

ii.

+ (void)sleepForTimeInterval:(NSTimeInterval)time;

6.死亡Dead:

+ (void)exit;

一旦线程停止(死亡)了,就不能再次开启任务。

(5)互斥锁

1.使用格式:

@synchronized(锁对象) {
    //需要锁定的代码
    }

2.优缺点:
i.优点:能有效防止因多线程抢夺资源造成的数据安全问题;
ii.缺点:需要消耗大量的CPU资源。

3.原理:
互斥锁,就是使用了线程同步技术,多线程在同一条线程上执行(按顺序地执行任务)。

三.NSOperation

(1)实现步骤

i.先将需要执行的操作封装到一个NSOperation对象中;
ii.然后将NSOperation对象添加到NSOperationQueue中;
iii.系统会自动将NSOperationQueue中的NSOperation取出来;
iiii.将取出的NSOperation封装的操作放到一条新线程中执行。

(2)子类

1.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类:
取消单个队列操作——>- (void)cancel;

2.NSInvocationOperation:
i.创建NSInvocationOperation对象——>- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
ii.调用start方法开始执行操作——>- (void)start;
iii.默认情况下,调用了start方法后并不会开一条新的线程去执行操作,而是在当前线程同步执行操作,只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。

3.NSBlockOperation:
i.创建NSBlockOperation对象——>+ (id)blockOperationWithBlock:(void(^)(void))block;
ii.通过addExecutionBlock:方法添加更多的操作——>- (void)addExecutionBlock:(void(^)(void))block;
iii.只要NSBlockOperation封装的操作数>1,就会异步执行操作。

4.自定义子类基础NSOperation:
i.重写- (void)main;方法,在里面实现想执行的任务;
ii.自己创建自动施法池(因为如果是异步操作,无法访问主线程的自动施法池);
iii.经常通过- (BOOL)isCancelled;方法检测操作是否被取消,对取消做出相应。

(3)NSOperationQueue

1.只要是自己创建的队列,就会在子线程中执行,而且默认并发

2.自动异步执行NSOperationQueue中NSOperation操作

3.添加操作到NSOperationQueue中:
- (void)addOperation:(NSOperation *)operation;
- (void)addOperationWithBlock:(void(^)(void))block;系统内部会自动封装成一个NSBlockOperation然后再添加到队列中。

4.最大并发数:
i.队列同时执行的任务数(队列属性);
ii.方法

- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

iii.maxConcurrentOperationCount默认为-1,不能取0。

5.取消、暂停、恢复:
i.暂停:self.queue.suspended = YES;
ii.恢复:self.queue.suspended = NO;
iii.取消:- (void)cancelAllOperations;
iiii.只会对后面未执行的任务进行操作,不会影响当前正执行的,且取消不可恢复。

(4)依赖

1.设置依赖来保证执行顺序,可以设置不同队列中的operation创建依赖关系

2.[operationB andDependency:operationA]; //操作B依赖操作A


四.GCD

(1)全称是Grand Central Dispatch

(2)GCD优势

1.GCD是苹果公司为多核的并行运算提出的解决方案;
2.GCD会自动利用更多的CPU内核(比如双核、四核);
3.GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程);
4.程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码。

(3)执行步骤

1.定制任务:
执行什么操作。
2.将任务添加到队列中:
i.GCD会自动将队列中的任务取出,放到相应的线程中执行;
ii.任务的取出遵循队列的FIFO原则:先进先出,后进后出。

(4)主要概念

1.同步:
只能在当前线程中执行任务,不具备开启新线程的能力。
2.异步:
具备开启新线程的能力。
3.并发:
i.可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务);
ii.并发功能只有在异步(dispatch_async)函数下才有效;
iii.使用dispatch_queue_create 函数创建队列;

dispatch_queue_t queue = dispatch_queque_create("com.apach3loveiOS.queue", DISPATCH_QUEUE_CONCURRENT);

iiii.使用dispatch_get_global_queue函数获得全局的并发队列;

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

4.串行:
i.让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务);
ii.使用dispatch_queue_create函数创建串行队列;

dispatch_queue_t queue = dispatch_queue_create("com.apach3loveiOS.queue", NULL);

iii.使用主队列:
- 1 -主队列是GCD自带的一种特殊的串行队列;
- 2 -放在主队列中的任务,都会放到主线程中执行;
- 3 -使用dispatch_get_main_queue()获得主队列。

dispatch_queue_t queue = dispatch_get_main_queue();

(5)队列类型

1.同步并发:
没有开启新线程,串行执行任务。
2.同步串行:
没有开启新线程,串行执行任务。
3.同步主队列:
没有开启新线程,串行执行任务。
4.异步并发:
开启新线程,并发执行任务。
5.异步串行:
开启一条新线程,串行执行任务。
6.异步主队列:
没有开启新线程,串行执行任务。

(6)其他方法

1.前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。
i.dispatch_barrier_async(dispatch_queue_t queue, dispatch_queue_block block);
ii.这个queue不能是全局的并发队列
2.延时执行:
i.[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
ii.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    //两秒之后执行这里的代码
});

iii.[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];
3.一次性代码:
i.保证某段代码在程序运行过程中只运行一次。
ii.

static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
       //只执行一次的代码(这里面默认是线程安全的)
   });

4.遍历:
i.能进行快速迭代遍历。
ii.

dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
       //执行十次代码,index顺序不确定
   });

加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值