》线程分为两种方式 --- 终起线程和非终起线程
终起线程 --- 任务执行完毕之后自动销毁
非终起线程 --- 任务执行完毕之后不自动销毁
1》.第一种实现方式 --- NSObject --- 隐式开辟一条线程 --- 终起线程 --- 最简单的实现方式
[self performSelectorInBackground:@selector(calculateNumber) withObject:nil]; - (void)calculateNumber { // 子线程里必须手动添加@autoreleasepool(自动释放池)--- 严格来讲 --- 涉及到堆内存(allock)的加@autoreleasepool @autoreleasepool { // 子线程 NSLog(@"%@ %d",[NSThread currentThread],[NSThread isMainThread]); for (int i = 0; i < 100; i++) { NSLog(@"%d",i); } }
2》.NSThread --- 终起线程 --- 两种方式
方式1:终起线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(calculateNumber) object:nil]; // 开始执行任务 [thread start];
方式2:非终起线程 --- 派遣新的线程 --- 自动开始
[NSThread detachNewThreadSelector:@selector(calculateNumber) toTarget:self withObject:nil]; // 获得当前线程 // NSThread *current = [NSThread currentThread]; // 给线程发送通知 --- 停止线程 // [current cancel]; // 直接结束线程 // [NSThread exit];
3》.NSOperation和NSOperationQueue --- 任务块和任务队列 --- 一个任务队列可以存放多个任务块
根据任务数量,CPU,和内存的使用情况,去开辟合适的线程数量 --- 用NSOperation的子类NSInvocationOperation,NSBlockOperation去初始化任务实例对象
NSInvocationOperation *ope1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(calculateNumber) object:nil]; // 创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 最多开辟的线程数 queue.maxConcurrentOperationCount = 5; // NO2 NSBlockOperation *ope2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"我是NSBlockOperation"); }]; // ope2放到队列中 [queue addOperation:ope2]; // 把任务快添加到队列 [queue addOperation:ope1];
》主队列不是线程,一般情况,主队列里面主线程去执行
NSOperationQueue mainQueue];
4》.GCD --- Grand Central Dispatch
iOS里面有很多实现多线程的方式,执行效率坐高的是GCD,是相对底层的API,全部有C实现,通过任务和队列的形式实现多线程
dispatch queue,它有两种队列:1.serial(串行队列)2.concurrent(并行队列)
》1.serial(串行队列)队列里面的任务,按照顺序依次执行,一个任务执行完成,再去执行下一个任务
serial队列的两种创建方式
第一种方式:
#pragma mark serial 第一种创建方式 - (IBAction)serial_mainSerialButtonDidClicked:(UIButton *)sender { dispatch_queue_t serialOneQueue = dispatch_get_main_queue(); // 主队列 // 往队列里面添加任务 // dispatch_sync(dispatch_queue_t queue, <#^(void)block#>) // 先执行block体内 代码块,在执行下面的代码 // dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>) // 不等block体内执行完毕,就立刻执行下面的代码 // 添加任务 dispatch_async(serialOneQueue, ^{ NSLog(@"第1个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第2个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第3个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第4个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第5个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第6个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第7个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第8个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第9个任务%@",[NSThread currentThread]); }); dispatch_async(serialOneQueue, ^{ NSLog(@"第十个任务%@",[NSThread currentThread]); }); }
第二种方式:
#pragma mark serial 第二种实现方式 - (IBAction)serial_userSerialButtonDIdClicked:(id)sender { // 第一个参数:队列的名字,苹果推荐使用反向域名是方式 第二个参数:队列的类型 1.serial(串行队列) 2.concurrent(并行队列) // 创建队列 dispatch_queue_t queue = dispatch_queue_create("com.lanou3g", DISPATCH_QUEUE_SERIAL); // 添加任务---它里面的任务 --- 会开辟一个子线程去执行 dispatch_async(queue, ^{ NSLog(@"第11个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第22个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第33个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第44个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第55个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第66个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第77个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第88个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第99个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第10个任务%@",[NSThread currentThread]); }); }
》2.concurrent(并行队列)--- 并行队列里面的任务,按照顺序开始执行,但是第二个任务不会等第一个任务结束才开始执行
--- 最终结果,队列里面的任务执行完成的顺序可能会跟开始进入队列的顺序不一致
第一种方式:
#pragma mark 并行队列的第一种方式(全局队列 --- GCD提供了三个全局队列) - (IBAction)GCDconCurrentFirstButtonDIdClicked:(UIButton *)sender { // 获取全局队列 --- 并行队列 --- 第一个参数:队列的优先级,共有4个优先级 background default high low 第二个参数:苹果预留的参数,目前没用,填0 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 添加任务 dispatch_async(queue, ^{ NSLog(@"第一个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第二个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第三个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第四个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第五个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第六个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第七个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第八个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第九个任务%@",[NSThread currentThread]); }); }
第二种方式:
#pragma mark 并行队列第二种方式 - (IBAction)GCDconCurrentSecondButtonDIdClicked:(UIButton *)sender { // 创建并行队列 dispatch_queue_t queue = dispatch_queue_create("com.lanoukeji", DISPATCH_QUEUE_CONCURRENT); // 添加任务 dispatch_async(queue, ^{ NSLog(@"第1个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第2个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第3个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第4个任务%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"第5个任务%@",[NSThread currentThread]); }); }
》3.延迟执行某个任务
#pragma mark 延迟执行某个任务 - (IBAction)GCD_delayButtonDIdClicked:(UIButton *)sender { // 1.第一种(分开写) /* double timeDelay = 3.0; dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeDelay*NSEC_PER_SEC); // 开始写任务 dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"我被延迟了3秒"); }); */ // 2.第二种方式 // double timeDelay = 3; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"我被延迟了2秒"); }); }
》4.GCD单次执行某个任务,这个任务在程序执行期间只执行一次
#pragma mark GCD单次执行某个任务,这个任务在程序执行期间只执行一次 - (IBAction)GCD_onceDidClicked:(UIButton *)sender { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"我解放了"); }); }
》5.指定某个任务,最后执行
#pragma mark 指定某个任务 最后执行 - (IBAction)GCD_groupDidClicked:(UIButton *)sender { // 创建一个组 // dispatch_group_t创建组的作用,把不同的任务归为一个小组 // dispatch_group_notify,组里的任务执行完毕之后,再去执行dispatch_group_notify的任务 dispatch_group_t group = dispatch_group_create(); // 创建队列 dispatch_queue_t queue = dispatch_queue_create("come.lanou", DISPATCH_QUEUE_CONCURRENT); // 添加任务 dispatch_group_async(group, queue, ^{ NSLog(@"第1个任务%@",[NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"第2个任务%@",[NSThread currentThread]); }); // 通过notify来添加组里任务 group里面的任务都执行完毕之后 再去执行notify里面的任务 // 最后执行的任务 dispatch_group_notify(group, queue, ^{ NSLog(@"我是group组里所有任务执行完毕之后才执行的任务"); }); dispatch_group_async(group, queue, ^{ NSLog(@"第6个任务%@",[NSThread currentThread]); }); }
》6.同时读 同时写
// 同时读 同时写 - (IBAction)GCD_barrierButtonDIdClidked:(UIButton *)sender { // 创建并行队列 dispatch_queue_t queue = dispatch_queue_create("come.lanou", DISPATCH_QUEUE_SERIAL); // 添加任务 dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); // 网数据库里面写入内容 dispatch_barrier_async(queue, ^{ NSLog(@"1网数据库里面写入内容,所在线程%@",[NSThread currentThread]); }); dispatch_barrier_async(queue, ^{ NSLog(@"2网数据库里面写入内容,所在线程%@",[NSThread currentThread]); }); dispatch_barrier_async(queue, ^{ NSLog(@"3网数据库里面写入内容,所在线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"读取数据库内容所在的线程%@",[NSThread currentThread]); }); }
》7.某个任务执行若干次
#pragma mark 某个任务执行若干次 - (IBAction)GCD_apply_moreTimeButtonDidClicked:(UIButton *)sender { NSArray *array = @[@"杨过",@"小龙女",@"黄老邪"]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // index参数自己加 --- 苹果bug dispatch_apply(array.count, queue, ^(size_t index) { NSLog(@"%@",array[index]); }); }
》8.函数指针
- (IBAction)GCD_functionButtonDidClicked:(UIButton *)sender { // 创建队列 --- 并行 dispatch_queue_t queue = dispatch_queue_create("come.lanou", DISPATCH_QUEUE_CONCURRENT); // 往队列里面添加任务 // dispatch_async_f往队列里面添加任务,不是控制block的执行,而是控制函数的执行,这些函数有要求:返回值必须是void 参数必须是void * dispatch_async_f(queue, @"你好", function); // 第二个参数可以是任意对象类型的数据 } #pragma mark 函数 void function(void *context) { NSLog(@"%@ %@",[NSThread currentThread],context); }