一 pthread :
/*
参数:
1.线程代号的地址
2.线程的属性
3.调用函数的指针
4.传递给函数的参数
返回值:
- 如果是 0, 表示正确
- 如果是非0,表示错误码
void *--(*)--(void *)
返回值--(函数指针)--(参数)
void * 相当于 OC中的id
*/
-(void)pthreadDemo{
pthread_t threadID;
NSString * str = @"hello 老王";
/*
- 在 ARC 开发中, 如果遇到 OC和C 语言中相同数据类型进行转换,需要使用__bridge "桥接"
- 在 MRC 开发中,不需要桥接
在 OC 中,如果是ARC开发,编译器会在编译的时候,自动根据代码结构,添加 retain , release, autorelease
ARC 只负责 OC部分的代码,不负责C的代码. 如果C的代码里面出现了 retain/create/copy 字样的函数,都需要release
*/
int result = pthread_create(&threadID, NULL, &demo, (__bridge void *)(str));
if (result == 0) {
for (int i = 0; i < 20; i++) {
NSLog(@"OK!");
}
}else{
NSLog(@"error %d",result);
}
}
void * demo(void *param){
NSString * sss = (__bridge NSString *)(param);
NSLog(@"%@---%@",[NSThread currentThread],sss);
return NULL;
}
一 NSThread
oc语言需要程序员手动管理线程
//创建线程 开辟一个子线程 常用创建方法
1 NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(demo:) object:@"thread"];
//启动线程
[thread start];
//创建以后立即开启
2 [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"];
//常用的方法
3 [self performSelectorInBackground:@selector(longOperation) withObject:nil];
延时操作
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
[NSThread sleepForTimeInterval:2.0];
杀死线程
//一旦强行终止线程,后续的所有的代码都不会执行
//注意:在终止线程之前,应该注意释放之前分配的对象!否则出现内存泄露!
4 [NSThread exit];
二 优先级属性
/*优先级
* 优先级只能保证 CPU 调度的可能性会高!
* 多线程的目的: 将耗时的操作放在后台,不阻塞主线程和用户的交互!
* 建议: 尽量不要修改 优先级!
* "优先级翻转"
* 在多线程开发中,不要相信你看到的结果!!一定要理性的(冷静)分析!!
*/
t2.threadPriority = 0.1;
三 资源共享
@synchronized
//参数:就是能够加锁的任意 NSOjbect 对象
//局部变量: 每个线程单独拥有的,无法锁住!!
//注意: 锁一定要是所有线程共享的对象!!
@synchronized (<#token#>) {
<#statements#>
//互斥锁 - 保证锁内的代码,同一时间,只有一条线程能够执行!!
//互斥锁它的范围,应该尽量小,锁范围越大,效率越低!
}
三 GCD 相关用法
1. 什么是GCD
全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
纯C语言,提供了非常多强大的函数
2. GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核 为以后苹果公司推出多核提供兼容)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
3.GCD中有2个核心概念
任务:执行什么操作
队列:用来存放任务
GCD的使用就2个步骤
定制任务
确定想做的事情
将任务添加到队列中
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循队列的FIFO原则:先进先出,后进后出
4 GCD常用方法
1. 延时操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
2 一次执行操作(设置单列的时候经常用到)
//GCD提供了一个一次执行的机制,不仅能够保证只会被执行一次.而且是线程安全的!
//GCD-Once 内部是会加锁!! 但是 比普通的互斥锁 效率高 100多倍 苹果推荐使用这个
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
3 调度组
//MARK: 调度组
-(void)group1{
//1.队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
//2.调度组
dispatch_group_t g = dispatch_group_create();
//3.添加任务,让队列执行,任务执行情况最终通知组
dispatch_group_async(g, q, ^{
NSLog(@"download A %@",[NSThread currentThread]);
});
dispatch_group_async(g, q, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"download B %@",[NSThread currentThread]);
});
dispatch_group_async(g, q, ^{
[NSThread sleepForTimeInterval:0.8];
NSLog(@"download C %@",[NSThread currentThread]);
});
//4. 所有任务执行完毕后,获得通知
//用一个调度组,可以监听全局队列调度的任务,执行完毕之后,在主队列执行最终处理!
//dispatch_group_notify 本身是异步的
dispatch_group_notify(g, dispatch_get_main_queue(), ^{
//更新UI,通知用户
NSLog(@"OK %@",[NSThread currentThread]);
});
NSLog(@"come here");
}
//MARK: 主队列,同步任务
//阻塞主线程!!
-(void)gcdDemo2{
//1.队列 -> 一启动就有主线程,主队列只需要获取
dispatch_queue_t q = dispatch_get_main_queue();
NSLog(@"这里!!");
//2.同步任务
dispatch_sync(q, ^{
NSLog(@"能来吗?");
});
NSLog(@"come here -- %@",[NSThread currentThread]);
}
5 GCD总结
/**
GCD 核心概念:将任务添加到队列,指定任务执行的方法
- 任务
- 使用block 封装
- block就是一个提前准备好的代码块,在需要的时候执行
- 队列(负责调度任务)
- 串行队列:一个接一个的调度任务
- 并发对象:可以同时调度多个任务
- 执行任务的函数
- 同步执行: 当前指令不完成,就不会执行下一条指令
- 异步执行: 当前执行不完成,同样可以执行下一条指令
小结:
- 开不开线程,取决于同步\异步. 同步,不开! 异步,开!
- 开多少条线程,取决于队列,串行开一条,并发(异步)开多条!
hank:开启子线程只能是异步!!! 线程多开\并发且异步
只要是异步就开启子线程!!!
全局队列 & 并发队列
1. 名称,并发队列有名称,适合大型项目跟踪错误报告!
2. release,在 MRC 开发时,并发队列需要使用 dispatch_release(q);
结论:目前绝大多数软件都会使用全局队列.
全局队列 & 串行队列
全局队列(并发): 并发,能够调度多个线程,执行效率高!!!
- 费电!!
串行队列: 一个接一个,只能开启一条线程,执行效率低!!
- 省电,省钱,省流量
选择的依据: 根据用户的上网方式!!
- WIFI ,可以开多条线程, 6条
- 3G\4G,尽量少开线程,2~3 条
四 NSOperation
特点: 不能直接使用
目的: 定义子类中共有的属性和方法
子类:- NSInvocationOperation - NSBlockOperation
1. 创建 // NSInvocationOperation 操作
NSInvocationOperation * op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:@"Hank"];
//start 方法,会在当前线程执行调度方法
// [op start];
//1.队列
NSOperationQueue * q = [[NSOperationQueue alloc]init];
//2.将操作添加到队列 - 会自动异步执行调度方法
[q addOperation:op];
2. //NSBlockOperation 所有的代码都写在一起.更加好维护
NSOperationQueue * q = [[NSOperationQueue alloc]init];
NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ ---- %d",[NSThread currentThread],i);
}];
[q addOperation:op];
二 线程间的通讯
[self.opQueue addOperationWithBlock:^{
NSLog(@"耗时操作!! %@",[NSThread currentThread]);
//主线程 更新UI ,主队列
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"UIUIUI --- %@",[NSThread currentThread]);
}];
}];
三 依赖关系
/**
需求:从网上下载视频\完成之后解码\通知用户
*/
//1.下载
NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:3.0];
NSLog(@"下载 - %@",[NSThread currentThread]);
}];
//2.解码
NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2.0];
NSLog(@"解码 - %@",[NSThread currentThread]);
}];
//3.通知用户
NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"通知用户 - %@",[NSThread currentThread]);
}];
//NSOperation 提供了依赖关系
//NSOperation 的所有的操作都是异步执行的,但是为了建立任务之间的依赖,提供了dependency的功能
//GCD中,通过同步任务来实现,也可以通过串行队列!
[op2 addDependency:op1];//op2 依赖于 op1 == op1 执行完毕 op2 开始执行
[op3 addDependency:op2];
// !!千万注意!!!: 不要循环依赖!!!!,一旦指定了循环依赖,队列就不能执行被循环依赖的操作了!!
//不会造成死锁! 但是 以前的版本 会死锁!!
// [op1 addDependency:op3];
[self.opQueue addOperations:@[op1,op2] waitUntilFinished:NO];
//主线程通知用户
[[NSOperationQueue mainQueue] addOperation:op3];
NSLog(@"come here");
四 取消线程
//提示: 取消操作,同样不会取消正在执行中的操作
[self.opQueue cancelAllOperations];
五 暂停/恢复线程
//在设置队列的暂停属性时,并不会判断队列中是否有操作!
//如果不希望用户产生困惑,可以提前做判断
//判断队列中当前是否有操作
if (self.opQueue.operationCount == 0){
NSLog(@"没有操作!!!");
return ;
}
if (self.opQueue.isSuspended) {
//在暂停的时候,队列中的操作数,是包含正在执行的操作!!
NSLog(@"继续 %tu",self.opQueue.operationCount);
self.opQueue.suspended = NO;
}else{
//再次继续运行的时候,如果之前执行的操作已经完成,队列中的操作数就只有未调度的了!!
NSLog(@"暂停 %tu",self.opQueue.operationCount);
self.opQueue.suspended = YES;
}
六 最大线程
//设置同时最大并发操作数量
//WIFI: 5~6
//2G/3G/4G: 2~3
self.opQueue.maxConcurrentOperationCount = 2;
//向队列添加任务
//从 iOS 8.0 开始,无论使用GCD 还是 NSOperation, 都会开启很多线程
//在 iOS 7.0 以前,GCD 通常只会开启 5 ~ 6 条线程!
//目前线程数量多说明:
//1.底层的线程池更大了,能够拿到的线程资源更多了!
//2.对控制同时并发的线程数,要求就更高!
GCD和NSOpration的比较
/*
NSOperation 是苹果公司大力推荐的"并发"技术! 开发者已经不需要关心线程以及线程的生命周期!
,而且我们逃离了GCD的 并发还是串行 异步还是同步!
NSOperation 的核心概念: 将"操作" 添加到 "队列"
GCD的核心概念: 将"任务"添加到队列,指定任务的执行函数(方法)
----------------------------------------------------------------------------------
GCD & NSOperation 的对比
GCD 在 iOS 4.0推出的,主要针对多核处理器做了优化的并发技术,是 C 语言!
- 将"任务"[block]"添加到"队列[串行/并发/主队列/全局],并且指定执行任务的函数[同步/异步]
- 线程间的通讯 dispatch_get_main_queue()
- 提供了一些 NSOperation 不具备的功能
- 一次执行(单例设计模式最常用)
- 延迟执行
- 调度组
- 等等...
NSOperation 在 iOS 2.0 推出的!
- 将操作[异步执行的任务] 添加到 队列[并发队列],就会立刻异步执行
- mainQueue
- 提供了一些 GCD 实现起来比较困难的功能
- 最大并发线程数
- 队列的暂停/继续
- 取消所有操作
- 指定操作之间的依赖关系(GCD 同步实现)
----------------------------------------------------------------------------------
NSOperation类是一个抽象类
特点:
- 不能直接使用
目的:
- 定义子类中共有的属性和方法
子类:
- NSInvocationOperation
- NSBlockOperation
*/
网友评论