iOS之多线程精髓
2016-03-04 14:31
405 查看
一个正在运行的程序叫做进程,线程是进程的基本执行单元。进程中的任务在线程中执行。
一个进程中默认有一条主线程,单一线程中任务执行是串行的。多条线程可以同时执行不同任务。
多线程原理
同一时间cpu只能处理一条线程,多线程并发执行,是CPU快速的在多条线程中切换形成的假象。
多线程的优点
能适当提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)
多线程的缺点
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享
主线程
主线程的主要作用
显示\刷新UI界面
处理UI事件(比如点击事件、滚动事件、拖拽事件等)
主线程的使用注意
别将比较耗时的操作放到主线程中
耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验
ios实现多线程的方案
pthread
通用的线程API,使用难度大
NSThread
使用更加面向对象,简单易用可以直接操作。
GCD
旨在替代NSThread等线程技术
充分利用设备多核
NSOperation
基于GCD 比GCD多了一些更简单实用的功能,更加面向对象
NSThread
创建、启动线程
NSThread*thread = [[NSThread
alloc] initWithTarget:self
selector:@selector(run)object:nil];
[thread start];
+ (NSThread *)mainThread; //获得主线程
- (BOOL)isMainThread; //是否为主线程
+ (BOOL)isMainThread; //是否为主线程
- (void)setName:(NSString *)n;
- (NSString*)name;
创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run)toTarget:self
withObject:nil];
隐式创建并启动线程
[self performSelectorInBackground:@selector(run)withObject:nil];
上述2种创建线程方式的优缺点
优点:简单快捷
缺点:无法对线程进行更详细的设置
启动线程
- (void)start;
// 进入就绪状态
->运行状态。当线程任务执行完毕,自动进入死亡状态
阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate*)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 进入阻塞状态
强制停止线程
+ (void)exit;
// 进入死亡状态
注意:一旦线程停止(死亡)了,就不能再次开启任务
互斥锁使用格式
@synchronized(锁对象) {
// 需要锁定的代码 }
注意:锁定1份代码只用1把锁,用多把锁是无效的
互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
GCD
优点:
<1> GCD 能够自动利用更多的CPU的核数(双核/四核)!
<2> GCD 会自动管理线程的生命周期.
1> dispatch_async + 全局并发队列 (可以开启多条线程)
[b] 2> dispatch_async + 自己创建的串行队列 (开启一条线程)
GCD开启多线程,
定制任务添加队列
用同步的方式执行任务
dispatch_sync(dispatch_queue_tqueue,
dispatch_block_tblock);
queue:队列
block:任务
用异步的方式执行任务
dispatch_async(dispatch_queue_tqueue,
dispatch_block_tblock);
使用dispatch_queue_create函数创建串行队列
使用dispatch_get_global_queue函数获得全局的并发队列
使用dispatch_get_main_queue()获得主队列
从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{
//执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(),^{
// 回到主线程,执行UI刷新操作
});
});
GCD延时,
iOS常见的延时执行有2种方式
调用NSObject的方法
[self performSelector:@selector(run)withObject:nil
afterDelay:2.0];
// 2秒后再调用self的run方法
使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 *
NSEC_PER_SEC)), dispatch_get_main_queue(),^{
//2秒后执行这里的代码...在哪个线程执行,跟队列类型有关
});
GCD单例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//只执行1次的代码(这里面默认是线程安全的)
});
ARC
提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedMusicTool {
if (_instance ==
nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance ==
nil) { // 防止创建多次
_instance = [[self
alloc] init];
}
}
}
return _instance;
}
p实现copyWithZone:方法
- (id)copyWithZone:(struct
_NSZone*)zone {
return _instance;
}
非ARC下添加方法
非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)
实现内存管理方法
- (id)retain {
return self; }
- (NSUInteger)retainCount {
return 1; }
- (oneway void)release{}
- (id)autorelease {
return self; }
.单例实现:(两种方式:互斥锁(@synchronized(self))和一次性代码(dispatch_once));
//(1)重写 allocWithZone:方法,在这里创建唯一的实例(注意线程安全). //alloc 内部都会调用这个方法.
+(instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance ==
nil) {
// 防止频繁加锁
@synchronized(self) {
if (_instance ==
nil) {
// 防止创建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
//(2)重写 copyWithZone:方法.
+(id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
NSOperation
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
创建NSInvocationOperation对象
- (id)initWithTarget:(id)targetselector:(SEL)selobject:(id)arg;
调用start方法开始执行操作
- (void)start;
创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperationQueue中的操作
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation*)op;
-(void)addOperationWithBlock:(void (^)(void))block
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
暂停和恢复队列
- (void)setSuspended:(BOOL)b;
//YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
设置NSOperation在queue中的优先级,可以改变操作的执行优先级
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
优先级的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
可以监听一个操作的执行完毕
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA];
一个进程中默认有一条主线程,单一线程中任务执行是串行的。多条线程可以同时执行不同任务。
多线程原理
同一时间cpu只能处理一条线程,多线程并发执行,是CPU快速的在多条线程中切换形成的假象。
多线程的优点
能适当提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)
多线程的缺点
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享
主线程
主线程的主要作用
显示\刷新UI界面
处理UI事件(比如点击事件、滚动事件、拖拽事件等)
主线程的使用注意
别将比较耗时的操作放到主线程中
耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验
ios实现多线程的方案
pthread
通用的线程API,使用难度大
NSThread
使用更加面向对象,简单易用可以直接操作。
GCD
旨在替代NSThread等线程技术
充分利用设备多核
NSOperation
基于GCD 比GCD多了一些更简单实用的功能,更加面向对象
NSThread
创建、启动线程
NSThread*thread = [[NSThread
alloc] initWithTarget:self
selector:@selector(run)object:nil];
[thread start];
+ (NSThread *)mainThread; //获得主线程
- (BOOL)isMainThread; //是否为主线程
+ (BOOL)isMainThread; //是否为主线程
- (void)setName:(NSString *)n;
- (NSString*)name;
创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run)toTarget:self
withObject:nil];
隐式创建并启动线程
[self performSelectorInBackground:@selector(run)withObject:nil];
上述2种创建线程方式的优缺点
优点:简单快捷
缺点:无法对线程进行更详细的设置
启动线程
- (void)start;
// 进入就绪状态
->运行状态。当线程任务执行完毕,自动进入死亡状态
阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate*)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 进入阻塞状态
强制停止线程
+ (void)exit;
// 进入死亡状态
注意:一旦线程停止(死亡)了,就不能再次开启任务
互斥锁使用格式
@synchronized(锁对象) {
// 需要锁定的代码 }
注意:锁定1份代码只用1把锁,用多把锁是无效的
互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
GCD
优点:
<1> GCD 能够自动利用更多的CPU的核数(双核/四核)!
<2> GCD 会自动管理线程的生命周期.
1> dispatch_async + 全局并发队列 (可以开启多条线程)
[b] 2> dispatch_async + 自己创建的串行队列 (开启一条线程)
GCD开启多线程,
定制任务添加队列
用同步的方式执行任务
dispatch_sync(dispatch_queue_tqueue,
dispatch_block_tblock);
queue:队列
block:任务
用异步的方式执行任务
dispatch_async(dispatch_queue_tqueue,
dispatch_block_tblock);
使用dispatch_queue_create函数创建串行队列
使用dispatch_get_global_queue函数获得全局的并发队列
使用dispatch_get_main_queue()获得主队列
从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{
//执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(),^{
// 回到主线程,执行UI刷新操作
});
});
GCD延时,
iOS常见的延时执行有2种方式
调用NSObject的方法
[self performSelector:@selector(run)withObject:nil
afterDelay:2.0];
// 2秒后再调用self的run方法
使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 *
NSEC_PER_SEC)), dispatch_get_main_queue(),^{
//2秒后执行这里的代码...在哪个线程执行,跟队列类型有关
});
GCD单例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//只执行1次的代码(这里面默认是线程安全的)
});
ARC
提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedMusicTool {
if (_instance ==
nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance ==
nil) { // 防止创建多次
_instance = [[self
alloc] init];
}
}
}
return _instance;
}
p实现copyWithZone:方法
- (id)copyWithZone:(struct
_NSZone*)zone {
return _instance;
}
非ARC下添加方法
非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)
实现内存管理方法
- (id)retain {
return self; }
- (NSUInteger)retainCount {
return 1; }
- (oneway void)release{}
- (id)autorelease {
return self; }
.单例实现:(两种方式:互斥锁(@synchronized(self))和一次性代码(dispatch_once));
//(1)重写 allocWithZone:方法,在这里创建唯一的实例(注意线程安全). //alloc 内部都会调用这个方法.
+(instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance ==
nil) {
// 防止频繁加锁
@synchronized(self) {
if (_instance ==
nil) {
// 防止创建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
//(2)重写 copyWithZone:方法.
+(id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
NSOperation
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
创建NSInvocationOperation对象
- (id)initWithTarget:(id)targetselector:(SEL)selobject:(id)arg;
调用start方法开始执行操作
- (void)start;
创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperationQueue中的操作
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation*)op;
-(void)addOperationWithBlock:(void (^)(void))block
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
暂停和恢复队列
- (void)setSuspended:(BOOL)b;
//YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
设置NSOperation在queue中的优先级,可以改变操作的执行优先级
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
优先级的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
可以监听一个操作的执行完毕
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA];
相关文章推荐
- ios 热修复
- ios 获取ios系统信息
- iOS CoreData数据迁移-迁移管理器迁移数据
- ios单例写法
- 让你的程序“飞”起来——性能优化
- IOS9 wifi助理
- iOS数组按中文关键字以字母序排序
- iOS 蓝牙开发那些事
- 一步步创建自己的 iOS 框架
- iOS 判断iphone ipad 系统版本
- iOS 数组排序
- iOS开发---计算两个日期的时间差
- iOS学习----------多线程(NSThread/GCD/NSOperation)
- 测试驱动下的iOS应用开发
- iOS深复制浅复制
- iOS推送开关
- iOS 并发:NSOperation 与调度队列入门(1)
- iOS 并发:NSOperation 与调度队列入门(1)
- 【Xamarin挖墙脚系列:Xamarin.IOS的程序的结构】
- iOS缓存