本文主要介绍 iOS 中多线程的实现方案,本文需要有 iOS 基础的同学观看,如果有什么问题欢迎留言联系。
iOS 中多线程的实现方案有 4 中,如图:
上图简单明了的介绍了 4 种方式的优缺点,下面我们主要从第二种方式 NSThread 开始。
1、NSThread
(1)创建线程的方式有三种
- /*
- 1、需要手动开启线程
- 开启了子线程
- */
- NSThread * firstThread = [[NSThread alloc] initWithTarget: self selector: @selector(run: ) object: @ [@"firstThread"]];
- //线程开始(需要手动开启)
- firstThread.name = @"first"; [firstThread start];
- /*
- 2、不需要手动开启线程
- 开启了子线程
- */
- [NSThread detachNewThreadSelector: @selector(run: ) toTarget: self withObject: @"secondThread"];
- /*
- 3、隐市创建方式
- 开启子线程
- */
- [self performSelectorInBackground: @selector(run: ) withObject: @ [@"performSelectorInBackground"]];
三种方式的运行结果
- 2016 - 03 - 04 10 : 48 : 56.373多线程demo[2307 : 48372](firstThread)-----<NSThread: 0x7fc3cac1b170 > {
- number = 2,
- name = first
- }
- 2016 - 03 - 04 10 : 48 : 56.373多线程demo[2307 : 48373] secondThread-----<NSThread: 0x7fc3cad05b80 > {
- number = 3,
- name = (null)
- }
- 2016 - 03 - 04 10 : 48 : 56.373多线程demo[2307 : 48374](performSelectorInBackground)-----<NSThread: 0x7fc3cad10770 > {
- number = 4,
- name = (null)
- }
从运行结果可以看出,每种方式都开启了子线程。
(2)其他的隐式方式
2、GCD(重要),自动管理内存,C 语言方法
两种队列:串行队列和并发队列
两个函数:同步函数 dispatch_sync 和异步函数 dispatch_async(决定了要不要开启新的线程)
队列与函数结合使用的不同情况:
(1)全局并发队列添加到异步函数中
- 1、用dispatch_async异步函数往并发队列中添加任务—————》同时开启了3个子线程 - (void) asyncGlobalQueue {
- // 获取一个全局的默认优先级的并发队列
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- // 2.添加任务到队列中 执行
- dispatch_async(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- dispatch_async(queue, ^{
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- });
- dispatch_async(queue, ^{
- NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
- });
- // 总结: 同时开启了3个线程
- }执行结果:2016 - 03 - 04 11 : 24 : 58.042多线程demo[2413 : 66032]----下载图片1-----<NSThread: 0x7fe798e38510 > {
- number = 2,
- name = (null)
- }
- 2016 - 03 - 04 11 : 24 : 58.042多线程demo[2413 : 66033]----下载图片3-----<NSThread: 0x7fe798e03720 > {
- number = 4,
- name = (null)
- }
- 2016 - 03 - 04 11 : 24 : 58.042多线程demo[2413 : 66031]----下载图片2-----<NSThread: 0x7fe798f0b4b0 > {
- number = 3,
- name = (null)
- }
(2)串行队列添加到异步函数中,开启了一条子线程
- 2、用dispatch_async异步函数往串行队列中添加任务————————》只开了一个线程执行任务 - (void) asyncSerialQueue {
- // 1.创建串行队列
- dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL);
- // 2.添加任务到队列中 执行
- dispatch_async(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- dispatch_async(queue, ^{
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- });
- dispatch_async(queue, ^{
- NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
- });
- // 总结: 只开1个线程执行任务
- }执行结果:2016 - 03 - 04 11 : 26 : 32.063多线程demo[2426 : 67047]----下载图片1-----<NSThread: 0x7f8dab521ff0 > {
- number = 2,
- name = (null)
- }
- 2016 - 03 - 04 11 : 26 : 32.064多线程demo[2426 : 67047]----下载图片2-----<NSThread: 0x7f8dab521ff0 > {
- number = 2,
- name = (null)
- }
- 2016 - 03 - 04 11 : 26 : 32.065多线程demo[2426 : 67047]----下载图片3-----<NSThread: 0x7f8dab521ff0 > {
- number = 2,
- name = (null)
- }
(3)用 dispatch_sync 同步函数往并发队列中添加任务,不会开启新的线程,并发队列失去了并发的功能
- 3、用dispatch_sync同步函数往并发队列中添加任务—————》不会开启新的线程,并发队列失去了并发的功能 - (void) syncGlobalQueue {
- // 1.获得全局的并发队列
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- // 2.添加任务到队列中 执行
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- });
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
- });
- // 总结: 不会开启新的线程, 并发队列失去了并发的功能
- }执行结果2016 - 03 - 04 11 : 31 : 42.592多线程demo[2456 : 69917]----下载图片1-----<NSThread: 0x7fe00a402310 > {
- number = 1,
- name = main
- }
- 2016 - 03 - 04 11 : 31 : 42.592多线程demo[2456 : 69917]----下载图片2-----<NSThread: 0x7fe00a402310 > {
- number = 1,
- name = main
- }
- 2016 - 03 - 04 11 : 31 : 42.593多线程demo[2456 : 69917]----下载图片3-----<NSThread: 0x7fe00a402310 > {
- number = 1,
- name = main
- }
(4)同步函数执行串行队列,不会开启子线程
- 4、用dispatch_sync同步函数往串行列中添加任务—————》不会开启新的线程 - (void) syncSerialQueue {
- // 1.创建串行队列(串行队列)
- dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL);
- // 2.添加任务到队列中 执行
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- });
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
- });
- // 3.释放资源
- // dispatch_release(queue); // MRC(非ARC)
- // 总结: 不会开启新的线程
- }执行结果2016 - 03 - 04 11 : 30 : 40.115多线程demo[2443 : 69121]----下载图片1-----<NSThread: 0x7fc5125086d0 > {
- number = 1,
- name = main
- }
- 2016 - 03 - 04 11 : 30 : 40.116多线程demo[2443 : 69121]----下载图片2-----<NSThread: 0x7fc5125086d0 > {
- number = 1,
- name = main
- }
- 2016 - 03 - 04 11 : 30 : 40.116多线程demo[2443 : 69121]----下载图片3-----<NSThread: 0x7fc5125086d0 > {
- number = 1,
- name = main
- }
(5)用 dispatch_sync 同步函数, 在主线程中往主队列中添加任务 : 任务无法往下执行,产生死锁(死循环)
- 5、用dispatch_sync同步函数,
- 在主线程中往主队列中添加任务: 任务无法往下执行——————— > 产生死锁(死循环) - (void) syncMainQueue {
- // 1.获得主队列
- dispatch_queue_t queue = dispatch_get_main_queue();
- // 2.添加任务到队列中 执行
- dispatch_sync(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- // dispatch_sync(queue, ^{
- // NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- // });
- // dispatch_sync(queue, ^{
- // NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
- // });
- }
(6)异步函数, 在主线程中往主队列中添加任务
- 6、使用dispatch_async异步函数,
- 在主线程中往主队列中添加任务特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务),任务在主线程执行,不会开启新的线程 - (void) asyncMainQueue {
- // 1.获得主队列(串行队列)
- dispatch_queue_t queue = dispatch_get_main_queue();
- // 2.添加任务到队列中 执行
- dispatch_async(queue, ^{
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- });
- }执行结果2016 - 03 - 04 11 : 35 : 42.321多线程demo[2485 : 72362]----下载图片1-----<NSThread: 0x7f82fa407d90 > {
- number = 1,
- name = main
- }
(7) 异步函数在全局并发队列中执行 group 中的任务,同步函数不能执行 group 中的任务
- //异步函数在全局并发队列中执行group中的任务
- - (void) asyncGlobalQueueGroup {
- //获取到全局并发队列
- dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_t group = dispatch_group_create();
- dispatch_group_async(group, global_queue, ^{
- for (int i = 0; i < 100; i++) {
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- }
- });
- dispatch_group_async(group, global_queue, ^{
- for (int i = 0; i < 100; i++) {
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- }
- });
- //结果:在异步线程中并发执行group中的任务
- }
3、NSOperation
NSOperation 是对 GCD 的封装,将 GCD 封装成 oc 对象方便使用,NSOperation 是抽象类,不能直接创建 NSOperation 的对象和调用对象方法,它有两个子类 NSBlockOperation 和 NSInvocationOperation,使用时要用这两个方法来创建 opreation 对象、调用方法。
使用 NSBlockOperation 和 NSInvocationOperation 将需要的任务进行封装,
- - (void) operation {
- //1、封装任务
- NSBlockOperation * blockOpreation = [NSBlockOperation blockOperationWithBlock: ^{
- for (int i = 0; i < 100; i++) {
- NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
- }
- }]; [blockOpreation addExecutionBlock: ^{
- for (int i = 0; i < 100; i++) {
- NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
- }
- }];
- //封装任务
- NSInvocationOperation * invocationOperation = [[NSInvocationOperation alloc] initWithTarget: self selector: @selector(run: ) object: @ [@"invocationOperation"]];
- //在blockOpreation中添加需要执行的任务
- //设置blockOpreation中任务的优先级为最高
- blockOpreation.queuePriority = NSOperationQueuePriorityVeryHigh;
- // NSInvocation *invovation = [[NSInvocation alloc]ini]
- // NSInvocationOperation *invoOpt = [[NSInvocationOperation alloc]initWithInvocation:<#(nonnull NSInvocation *)#>]
- //2、创建队列
- NSOperationQueue * optQueue = [[NSOperationQueue alloc] init];
- //最大并发数
- optQueue.maxConcurrentOperationCount = 1;
- //添加依赖,当blockOpreation中的任务执行完毕在执行invocationOperation中的任务
- [invocationOperation addDependency: blockOpreation];
- //将任务添加到队列中自动执行
- [optQueue addOperations: @ [blockOpreation, invocationOperation] waitUntilFinished: YES];
- }
来源: http://lib.csdn.net/article/ios/43474