iOS 多线程

iOS多线程-NSThread

2016-06-13  本文已影响188人  simuty

一、基本概念

1.计算机操作系统都有的基本概念,以下概念简单方式来描述。

1 进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动。可以理解成一个运行中的应用程序。
2 线程: 程序执行流的最小单元,线程是进程中的一个实体。
3 队列: 装载线程任务的队形结构。

2.苹果官方定义

The term thread is used to refer to a separate path of execution for code.
The term process is used to refer to a running executable, which can encompass multiple threads.

线程用于指代一个独立执行的代码路径
进程用于指代一个可执行程序,他可以包含多个线程

Paste_Image.png

3.同步和异步主要影响:能不能开启新的线程

1 同步:只是在当前线程中执行任务,不具备开启新线程的能力
2 异步:可以在新的线程中执行任务,具备开启新线程的能力

4.并发和串行主要影响:任务的执行方式

1 并发:多个任务并发(同时)执行
2 串行:一个任务执行完毕后,再执行下一个任务

注意:
  1. 一个进程可有多个线程。
  2. 一个进程可有多个队列。
  3. 队列可分并发队列和串行队列。

二.NSThread API

1. 线程创建的两种方式
//直接创建并启动一个线程去Selector
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
//线程创建出来之后需要手动调用-start方法启动
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);

2. 线程操作之------启动,睡眠,取消,退出

Paste_Image.png
1. 启动
使用init方式创建需要手动- (void)start;

例子-

//init初始化
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(thread:) object:@"thread"];
// 开启线程
[thread start];

例子二

//创建并自动开启方法
[NSThread detachNewThreadSelector:@selector(thread1:) toTarget:self withObject:@"thread1"];

2. 线程睡眠的两种方法
//根据NSDate传入睡眠时间
+ (void)sleepUntilDate:(NSDate *)date;
//直接传入NSTimeInterval
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

NSThread的sleepUntilDate与runloop的runUntilDate:
深入理解RunLoop

![1.jpg](https://img.haomeiwen.com/i326255/a503a03b9938f3ad.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

sleepUntilDate:相当于执行一个sleep的任务。在执行过程中,即使有其他任务传入runloop,runloop也不会立即响应,必须sleep任务完成之后,才会响应其他任务
runUntilDate:虽然会阻塞线程,阻塞过程中并不妨碍新任务的执行。当有新任务的时候,会先执行接收到的新任务,新任务执行完之后,如果时间到了,再继续执行runUntilDate:之后的代码

例子:

//让线程睡眠2秒(阻塞2秒)
[NSThread sleepForTimeInterval:2];
//直接传入NSTimeInterval

[NSThread sleepUntilDate:[NSDate datewithTimeIntervalSinceNow:2]];

3.取消

对于线程的取消,NSThread提供了一个取消的方法和一个属性,调用-cancel方法并不会立刻取消线程,它仅仅是将cancelled属性设置为YES。cancelled也仅仅是一个用于记录状态的属性。线程取消的功能需要我们在main函数中自己实现

- (void)cancel NS_AVAILABLE(10_5, 2_0);

要实现取消的功能,我们需要自己在线程的main函数中定期检查isCancelled状态来判断线程是否需要退出,当isCancelled为YES的时候,我们手动退出。如果我们没有在main函数中检查isCancelled状态,那么调用-cancel将没有任何意义

5.退出

与充满不确定性的-cancel相比,-exit函数可以让线程立即退出。

+ (void)exit;

-exit属于核弹级别终极API,调用之后会立即终止线程,即使任务还没有执行完成也会中断。这就非常有可能导致内存泄露等严重问题,所以一般不推荐使用。

三. 线程之间的通讯

1. 从主线程把耗时的任务丢给辅助线程,当任务完成之后辅助线程再把结果传回主线程传,这些线程通讯一般用的都是perform方法
//将selector丢给主线程执行,可以指定runloop mode
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array; 

//将selector丢给主线程执行,runloop mode默认为common mode
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait; 
 
//将selector丢个指定线程执行,可以指定runloop mode
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array NS_AVAILABLE(10_5, 2_0);

//将selector丢个指定线程执行,runloop mode默认为default mode
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);


2. 主线程相关

// 获得主线程
+ (NSThread *)mainThread;

// 是否为主线程
- (BOOL)isMainThread;

// 是否为主线程
+ (BOOL)isMainThread;
// 获得当前线程
NSThread *current = [NSThread currentThread];


3. 线程优先级

3.1 NSQualityOfService主要有5个枚举值,优先级别从高到低排布:

1. NSQualityOfServiceUserInteractive:最高优先级,主要用于提供交互UI的操作,比如处理点击事件,绘制图像到屏幕上
2. NSQualityOfServiceUserInitiated:次高优先级,主要用于执行需要立即返回的任务
3. NSQualityOfServiceDefault:默认优先级,当没有设置优先级的时候,线程默认优先级
4. NSQualityOfServiceUtility:普通优先级,主要用于不需要立即返回的任务
5. NSQualityOfServiceBackground:后台优先级,用于完全不紧急的任务

一般主线程和没有设置优先级的线程都是默认优先级。

3.2 线程的调度优先级 priority(优先级)

+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;

调度优先级的取值范围是0.0 - 1.0,默认0.5,值越大,优先级越高

4. 线程通知

通知相关的三种形式

//由当前线程派生出第一个其他线程时发送,一般一个线程只发送一次
NSString * const NSWillBecomeMultiThreadedNotification;
//这个通知目前没有实际意义,可以忽略
NSString * const NSDidBecomeSingleThreadedNotification;
//线程退出之前发送这个通知
NSString * const NSThreadWillExitNotification;

例子



- (void)viewdidload{
// 创建线程
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain) object:nil]; 
//设置线程优先级
self.thread.qualityOfService = NSQualityOfServiceDefault; 
//启动线程
[self.thread start]; 

}



- (void)threadMain {
 //给线程设置名字. 可以不设置
    [[NSThread currentThread] setName:@"myThread"]; 
   // 给线程添加runloop
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
    //给runloop添加数据源   
   [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 
      
      //④:检查isCancelled
    while (![[NSThread currentThread] isCancelled]) {          
    //⑤启动runloop
        [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];  
    }
}



参考: iOS多线程篇

二、iOS多线程对比

  1. NSThread

每个NSThread对象对应一个线程,真正最原始的线程。

1)优点:NSThread 轻量级最低,相对简单。

2)缺点:手动管理所有的线程活动,如生命周期、线程同步、睡眠等。

  1. NSOperation

自带线程管理的抽象类。

1)优点:自带线程周期管理,操作上可更注重自己逻辑。

2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

  1. GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。

1)优点:最高效,避开并发陷阱。

2)缺点:基于C实现。

  1. 选择小结

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

更多精彩内容请关注“IT实战联盟”哦~~~


IT实战联盟.jpg
上一篇下一篇

猜你喜欢

热点阅读