一个NSThread对象就代表一条线程
以下线程启动就会执行run方法
1、
创建线程并手动启动
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
2、
创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
3、
隐式创建并启动线程
[self performSelectorInBackground:@selector(run) withObject:nil];
主线程
+ (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
当前线程
NSThread *current = [NSThread currentThread];
优先级
调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
线程名
- (void)setName:(NSString *)n; - (NSString *)name;
启动线程
- (void)start;
阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
强制停止线程
+ (void)exit;
注意:一旦线程停止(死亡)了,就不能再次开启任务
// 锁定1份代码只用1把锁,用多把锁是无效的
// 常用锁对象为self
@synchronized(锁对象) { // 需要锁定的代码 }
互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
互斥锁的使用前提
多条线程抢夺同一块资源
OC在定义属性时有nonatomic和atomic两种选择
atomic加锁原理
@property (assign, atomic) int age;
- (void)setAge:(int)age
{
@synchronized(self) {
_age = age;
}
}
nonatomic和atomic对比
- atomic:线程安全,需要消耗大量的资源
- nonatomic:非线程安全,适合内存小的移动设备
建议:
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
// 在主线程中执行方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; // 在对应线程中执行方法 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
同步的方式
在当前线程中执行,不会开启新线程
// queue 队列
// block 任务
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
异步的方式
在另一条线程中执行,可以开启新线程
// queue 队列
// block 任务
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
并发队列
可让多个任务并发执行,即同时开启多个线程执行任务
要实现并发功能,只能使并发队列在异步函数下有效。
串行队列
让任务按顺序一个一个执行。
获取全局并发队列
// identifier 优先级
// DISPATCH_QUEUE_PRIORITY_HIGH 2
// DISPATCH_QUEUE_PRIORITY_DEFAULT 0
// DISPATCH_QUEUE_PRIORITY_LOW -2
// DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
// 事例
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
获取串行队列
// 1 创建队列
// label 队列名
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
// 需要对创建的线程进行释放(MRC)
void dispatch_release(dispatch_object_t object);
// 2 获取主队列
// 主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务都会放到主线程中执行
dispatch_queue_t dispatch_get_main_queue(void);
1、 凡是函数名种带有create\copy\new\retain等字眼, 都需要在不需要使用这个数据的时候进行release
2、GCD的数据类型在ARC环境下不需要再做release
3、CF(Core Foundation)的数据类型在ARC环境下还是需要再做release
队列执行效果
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
});
使用场所:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的group中异步操作都执行完毕后,回到主线程...
});