多线程一些理解
iOS多线程几种实现方案
1.pthread . C语言但是使用难度大,用于Windows,Linux等平台,几乎不用
2.NSThread OC 简单易用,直接操作线程对象,但是偶尔使用。
3.GCD C语言 是为了替代NSThread等线程计数,充分利用设备多核,自动管理所以经常使用。
4.NSOperation OC语言,基于GCD 自动管理,所以也是经常使用。
1.在pthread中要实现它的子线程,导入<pthread.h>,pthread_t thread;pthread_create($thread,NULL,函数名,NULL);实现函数方法,比如void * run(void *param){for 循环一下,return NULL;}
2.NSThread
首先是创建线程
- (void)viewDidLoad { [super viewDidLoad]; NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:nil]; [thread start]; } -(void)run:(NSString *)param{ for (int i=0; i<10000; i++) { NSLog(@"%@--%@",param,[NSThread currentThread].name); } }
启动线程
还有一种创建线程的方式
[self performSelectorInBackground:(nonnull SEL) withObject:(nullable id)] [self performSelectorOnMainThread:(nonnull SEL) withObject:(nullable id) waitUntilDone:(BOOL)]
以上都不是很完美的方式
/*******************************************************/
3.GCD
全称:Grand Central Dispatch 牛逼的中枢调度器
为多核并行解决方案,自动利用CPU内核。自动管理生命周期,不需要编写任何线程管理代码
两个核心概念:任务和队列
两个步骤:定制任务和添加任务
//异步 具备开启新线程的能力 dispatch_async(dispatch_queue_t queue, ^{ code }) //同步 dispatch_sync(dispatch_queue_t queue, ^{ code })
queue 队列 block 任务
GCD队列的两大类型
并发队列 只有在异步才有效,多个任务并发执行
串行队列 一个任务完成后,才开始执行下一个任务
创建并发队列
dispatch_queue_t queue = dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
多线程安全隐患
1.多个线程可能会访问同一块资源。比如多个线程访问同一个对象,同一个变量和文件。想象存钱和取钱的例子。会覆盖之前的数据,无法实时更新提示。
2.解决方案就是加一把锁。互斥锁。等一个线程访问完毕后就解除锁。@synchronized(锁对象self)但是它会消耗大量CPU资源。不建议使用
原子核非原子属性
nonatomic
非线程安全,适合内存小的移动设备,所以所有的属性声明都是nonatomic
尽量避免多线程抢夺同一资源
atomic
原子属性 为setter方法,需要消耗大量资源
线程之间的通信
一个进程中,线程不是孤立 的,多个线程之间需要通信,比如在主线程中我们添加UI控件,图片等,在子线程中下载图片,下载完毕之后,要在主线程中显示图片
栅栏barrier,先执行前面的任务才执行后面的。
延迟执行:
[self performSelector:(nonnull SEL) withObject:(nullable id) afterDelay:(NSTimeInterval)];
GCD延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });
NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
一次性代码
使用dispatch_once保证某段代码在整个程序运行过程中只执行一次
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ });
GCD单例模式
设计模式
保证在程序运行时,一个类只有一个实例,而且该实例易于供外界访问。
使用场合
1.在整个引用程序中,共享一份资源(这份资源只需要创建初始化一次)
static id _instance; +(instancetype)allocWithZone:(struct _NSZone *)zone { @synchronized(self) { if (_instance == nil) { _instance = [super allocWithZone:zone]; } } return _instance; } +(instancetype)sharedInstance { @synchronized(self) { if (_instance == nil) { _instance = [[self alloc]init]; } } return _instance; } -(id)copyWithZone:(NSZone *)zone { return _instance; }
利用宏写单例。
##代表替代的单例名称
\代表指针指向,强指针
#define XiaoSingleH(name) + (instancetype)shared##name; #define XiaoSingleM\ static id _instance;\ +(instancetype)allocWithZone:(struct _NSZone *)zone\ {\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [super allocWithZone:zone];\ });\ return _instance;\ }\ +(instancetype)sharedInstance\ {\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ _instance = [[self alloc]init];\ });\ return _instance;\ }\ -(id)copyWithZone:(NSZone *)zone\ {\ return _instance;\ }\
NSOperation
一、NSOperation简介
1.简单说明
NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤:
(1)先将需要执行的操作封装到一个NSOperation对象中
(2)然后将NSOperation对象添加到NSOperationQueue中
(3)系统会⾃动将NSOperationQueue中的NSOperation取出来
(4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏
2.NSOperation的子类
NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类
使用NSOperation⼦类的方式有3种:
(1)NSInvocationOperation
(2)NSBlockOperation
(3)自定义子类继承NSOperation,实现内部相应的⽅法
二、 具体说明
1.NSInvocationOperation子类
创建对象和执行操作:
1 //创建操作对象,封装要执行的任务 2 //NSInvocationOperation 封装操作 3 NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil]; 4 5 //执行操作 6 [operation start];
操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作 .
3.NSOperationQueue
NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中,自动执行操作,自动开启线程
一、并发数
(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3
(2)最大并发数:同一时间最多只能执行的任务的个数。
(3)最⼤大并发数的相关⽅方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
注意:num的值并不代表线程的个数,仅仅代表线程的ID。
提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
二、队列的取消,暂停和恢复
(1)取消队列的所有操作
- (void)cancelAllOperations;
提⽰:也可以调用NSOperation的- (void)cancel⽅法取消单个操作
(2)暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended; //当前状态
(3)暂停和恢复的适用场合:在tableview界面,开线程下载远程的网络界面,对UI会有影响,使用户体验变差。那么这种情况,就可以设置在用户操作UI(如滚动屏幕)的时候,暂停队列(不是取消队列),停止滚动的时候,恢复队列。
三、操作优先级
(1)设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
(2)优先级的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
说明:优先级高的任务,调用的几率会更大。
浙公网安备 33010602011771号