•NSThread:
–优点:NSThread 比其他两个轻量级,使用简单
–缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销
//创建线程方法1
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(threadAction:) object:nil];
[thread start];//开启子线程
[thread cancel];//取消子线程
//创建线程方法2-立即在线程中执行任务
[NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:nil];
//创建线程方法3-在后台子线程中执行任务
[self performSelectorInBackground:@selector(threadAction:) withObject:nil];
-(void)threadAction:(id*)sender{
@autoreleasepool {
//子线程中通知主线程通常使用以下两种办法
// [self.imageview performSelectorOnMainThread:@selector(updateView:) withObject:nil waitUntilDone:YES];
// [self.imageview performSelector:@selector(updateView:) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
}
}
线程下载完图片后怎么通知主线程更新界面呢?
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的
//NSOperationQueue
//两种操作-(操作本身跟多线程关系不大)
//NSInvocationOperation
//NSBlockOperation
NSInvocationOperation *inop = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(inopAction:) object:nil];
//[inop start];
NSBlockOperation *blop = [NSBlockOperation blockOperationWithBlock:^{
@autoreleasepool { NSLog(@"blop"); } }];
//队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//1的话顺序执行
//同时执行最大操作数
queue.maxConcurrentOperationCount = 3;
//依赖关系
[inop addDependency:blop];//blop执行完,才能执行inop
//向队列添加操作
[queue addOperation:inop];
[queue addOperation:blop];
-(void)inopAction:(id)sender{
@autoreleasepool { NSLog(@"inop"); }
}
关于并发数
(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3
(2)最大并发数:同一时间最多只能执行的任务的个数。
(3)最⼤大并发数的相关⽅方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
注意:num的值并不代表线程的个数,仅仅代表线程的ID。
提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
The main queue: 与主线程功能相同。实际上,提交⾄至main queue的任务会在主线程中执⾏行。main queue可以调⽤用dispatch_get_main_queue()来获得。因为mainqueue是与主线程相关的,所以这是⼀一个串⾏行队列。
Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:⾼高、中(默认)、低、后台四个优先级队列。可以调⽤用dispatch_get_global_queue函数传⼊入优先级来访问队列。优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_sync(),同步添加操作。等待添加进队列里面的操作完成之后再继续执行。调用以后等到block执行完以后才返回 ,dispatch_sync()会阻塞当前线程。
dispatch_async ,异步添加进任务队列,调用以后立即返回,它不会做任何等待
在多线程开发当中,程序员只要将想做的事情定义好,并追加到DispatchQueue(派发队列)当中就好了。
派发队列分为两种,一种是串行队列(SerialDispatchQueue),一种是并行队列(ConcurrentDispatchQueue)。
一个任务就是一个block,比如,将任务添加到队列中的代码是:
1 dispatch_async(queue, block);
当给queue添加多个任务时,如果queue是串行队列,则它们按顺序一个个执行,同时处理的任务只有一个。
当queue是并行队列时,不论第一个任务是否结束,都会立刻开始执行后面的任务,也就是可以同时执行多个任务。
但是并行执行的任务数量取决于XNU内核,是不可控的。比如,如果同时执行10个任务,那么10个任务并不是开启10个线程,线程会根据任务执行情况复用,由系统控制。
延时的实现
//第一种NSThread延时
[NSThread sleepForTimeInterval:3];//延时3秒-阻塞主线程
//第二种
[self performSelector:@selector(dosth) withObject:nil afterDelay:2];//延时3秒执行,不会阻塞主线程
//第三种GCD 3秒回到主线程执行 不会阻塞主线程
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{NSLog(@"第三种");} );
//第四种 GCD
dispatch_queue_t qq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)4*NSEC_PER_SEC), qq, ^{
NSLog(@"第四种");
});
-(void)dosth{
NSLog(@"第二种");
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"group1");
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"group2");
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"group3");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"updateUi");
});
dispatch_release(group);
//重复执行
//放到全局队列才执行
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t t) {
NSLog(@"重复执行,%ld",t);
});