美文网首页iOS开发随谈
iOS开发之多线程(一)

iOS开发之多线程(一)

作者: cp__kong | 来源:发表于2019-05-06 21:07 被阅读1次

目录

  • 概要
  • NSThread
  • GCD
  • NSOperation
  • 多线程与锁

1.概要

  • 进程
 进程指系统中独立正在运行的程序,每个进程都运行在其专用且受保护的内存空间中。
  • 线程
线程是进程的基本执行但也,一个进程(程序)的所有任务都在线程中执行,每个进程至少要有一个线程。

1个线程中任务的执行是串行的。
  • 多线程
1个进程可以开启多条线程,每条线程可以并行(同时)执行不同的任务。
  • 多线程的原理
 同一时间,CPU只能处理一条线程,只有1条线程工作(执行)。

>多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)。

如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象。
  • 多线程优缺点

优点

  • [ ] 能适当提高程序的执行效率。

  • [ ] 能适当提高资源利用率(CPU、内存利用率)

缺点

  • [ ] 开启线程需要占用一定的内存空间(默认情况下,主线城占用1M,子线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。

  • [ ] 线程越多,CPU在调度线程上的开销就越大。

  • [ ] 会使得程序开发变得复杂。

  • 主线程

一个iOS程序运行后,默认开启一条线程,成为‘主线程’或‘UI线程’,主要负责显示/刷新UI界面,处理UI事件。注意:别将比较耗时的操作放到主线程中

多线程实现方式

  1. pthread
  • [ ] 简介:

    1.一套通用的多线程API
    2.适用Unix\Linux\Windows等系统
    3.跨平台\可移植
    4.使用难度大
    

C语言,线程生命周期需要程序员管理,几乎不用

  1. NSThread
  • [ ] 简介:
    1.使用更加面向对象
    2.简单易用,可直接操作线程对象

OC,线程生命周期需要程序员管理,偶尔使用

  1. GCD(Grand Central Dispatch)
  • [ ] 简介:
    1.用来替代NSThread等技术
    2.充分利用设备的多核

C语言,线程生命周期自动管理,经常使用

  1. NSOperation
  • [ ] 简介:

    1.基于GCD(底层是GCD)
    2.比GCD多了一些更简单实用的功能
    3.使用更加面向对象
    

OC语言,线程生命周期自动管理,经常使用

NSOperation是个抽象类,并不具备封装操作的能力,必须使用他的子类。

使用NSOperation子类的方式有3种

  • [ ] NSInvocationOperation
  • [ ] NSBLockOperation
  • [ ] 自定义子类继承NSOperation,实现内部相应的方法。

2.NSThread

  • [ ] 创建、启动线程
//方式1:创建线程后手动启动
NSThread *thread = [[NSthread alloc] initWithTarget:self selectot:@selectot(run) object:nil];
[thread start];

//方式2:创建线程后自动启动
[NSthread detachNewThreaSelectot:@selectot(run) toTarget:self withObject:nil];

//方法3:隐式创建线程并自动启动
[self performSelectInBackground:@selector(run) withObject:nil];
  • [ ] 相关方法
+ (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; //是否为主线程
+ (BOOL)isMainThread; //是否为主线程
+ (NSThread *)currentThread; // 获得当前线程
//线程的调度优先级
+ (double)threadPriorty;
+ (BOOL)setThreadPriorty:(double)p;
-(double)threadPriorty;
- (BOOL)setThreadPriorty:(double)p;
//调度优先级的取值为0.0~1.0,默认为0.5,值越大,优先级越高。

//线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
  • [ ] 控制线程状态
//启动线程
- (void)start;
//进入就绪状态->运行状态。当线程任务执行完毕,自动进入死亡状态。

//阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//进入阻塞状态

//强制停止线程
+ (void)exit;
//进入死亡状态

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

3. GCD(Grand Central Dispatch)

队列的执行顺序FIFO(先进先出)

  • [ ] 同步和异步
  1. 同步(sync): 只能在当前线程中执行任务,不具备开启新线程的能力
  2. 异步(async): 可以在新的线程中执行任务,具备开启新线程的能力
  • [ ] 并发队列和串行队列
  1. 并发队列: 可以让多个任务并发执行,并发功能只有在异步函数下才有效
  2. 串行队列: 让任务一个接着一个地执行

注意

同步和异步主要决定能不能开启新线程
并发和串行决定执行方式

几种组合情况

  1. async + 并发队列(最常用)

会创建线程,同时开启多条,任务并发执行

  1. async + 串行队列(有时候用)

会开一条线程,串行执行

  1. sync + 串行队列

不会开启线程,串行执行

  1. sync + 并发队列

不会开启线程,串行执行

  1. async + 主队列(添加到主队列中的任务,都会自动放到主线程中执行)

主要用于线程通信

  1. sync + 主队列(不能用)

主队列中串行执行,同步函数互相等待,死锁


4. NSOperation

使用NSOperation子类的方式有3种

  • [ ] NSInvocationOperation
  • [ ] NSBLockOperation
  • [ ] 自定义子类继承NSOperation,实现内部相应的方法。

NSOperationQueue的一些高级用法

1.设置最大并发数为2条
queue.maxConcurrentOperationCount = 2;

2.线程依赖(不能互相依赖)
【operationB addDependency:operationA];
【operationC addDependency:operationB];

3.取消队列的所有操作
- (void)cancelAllOperations;
//也可以调用NSOperation的 - (void)cancel 方法取消单个操作

4.暂停和恢复队列
- (void) setSuspended:(BOOL)b;//YES表示暂停队列,NO代表恢复队列

5.主队列
[NSOperationQueue mainQueue];
//添加到主队类的操作会在主线程运行,放在其他队列的操作在子线程运行

6.线程通信
 [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //回到主线程需要的操作
 }];

自定义NSOperation

自定义NSOperation的步骤很简单
重写- (void)main方法,在里面实现想执行的任务

重写- (void)main方法的注意点
自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应

4.多线程与锁

多线程中的隐患

  • 资源抢夺:一块资源可能被多个线程共享,会产生资源竞争,造成数据混乱。

解决方案:加锁(后续补充)

  • [x] 互斥锁:

使用格式:

@synchronized(锁对象){
    //需要锁定的代码
}
**注意:**锁定1份代码只用一把锁,用多把锁是无效的

互斥锁的优缺点:

优点: 能有效防止因多线程抢夺资源造成的数据安全问题

缺点: 需要销毁大量的CUP资源

互斥锁的使用前提: 多条线程抢夺同一块资源


线程之间的通信

// 回到主线程,刷新UI界面(为了线程安全)
1.[self performSelectorOnMainThread:@selector(downloadFinished:) withObject:image waitUntilDone:NO];
2.[self performSelector:@selector(downloadFinished:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];

或者直接用对象调用 [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

注意:  waitUntilDone后面的参数表示是否等待线程通讯完毕

//GCD回到主线程
disptach_async(dispatch_get_main_queue(),^{
    //回到主线程需要的操作
})

//NSOperationQueue
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //回到主线程需要的操作
    }];
    


延时

// 延迟执行不要用sleep,坏处:卡住当前线程
 1.   [NSThread sleepForTimeInterval:3];
 
 // 一旦定制好延迟任务后,不会卡主当前线程
 2.   [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];

 // 3秒后自动开启新线程 执行block中的代码
3.    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"------task------%@", [NSThread currentThread]);
    });

相关文章

网友评论

    本文标题:iOS开发之多线程(一)

    本文链接:https://www.haomeiwen.com/subject/wrhjoqtx.html