美文网首页
iOS 多线程详解

iOS 多线程详解

作者: 依米米一 | 来源:发表于2020-04-27 23:23 被阅读0次
    多线程简图
    区分

    NSThread

    三种创建方式

    /** 方法一,创建好之后自动启动 */
        [NSThread detachNewThreadSelector:@selector(doSomething1:) toTarget:self withObject:@"NSThread1"];
        
        /** 方法二,隐式创建,直接启动 */
        [self performSelectorInBackground:@selector(doSomething2:) withObject:@"NSThread2"];
        
        /** 方法三,需要start */
        NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething3:) object:@"NSThread3"];
        // 线程加入线程池等待CPU调度,时间很快,几乎是立刻执行
        [thread3 start];
    
     /** 休眠 */
      [NSThread sleepForTimeInterval:2];
       //休眠到指定时间
       [NSThread sleepUntilDate:[NSDate date]];
       
       NSLog(@"doSomething----:%@",[NSThread currentThread]);
       //设置优先级
        thread1.threadPriority;
    - (void)doSomething1:(NSObject *)object {
        // 传递过来的参数
        NSLog(@"%@",object);
        NSLog(@"doSomething1:%@",[NSThread currentThread]);
    }
    - (void)doSomething2:(NSObject *)object {
        NSLog(@"%@",object);
        NSLog(@"doSomething2:%@",[NSThread currentThread]);
    }
    - (void)doSomething3:(NSObject *)object {
        NSLog(@"%@",object);
        NSLog(@"doSomething3:%@",[NSThread currentThread]);
    }
    

    输出结果

    2020-04-27 12:04:25.036396+0800 demoTest[63761:2343201] doSomething3:<NSThread: 0x600000efcb80>{number = 7, name = (null)}
    2020-04-27 12:04:25.036396+0800 demoTest[63761:2343199] doSomething1:<NSThread: 0x600000efcac0>{number = 5, name = (null)}
    2020-04-27 12:04:25.036397+0800 demoTest[63761:2343200] doSomething2:<NSThread: 0x600000efc900>{number = 6, name = (null)}
    2020-04-27 12:04:27.037067+0800 demoTest[63761:2343124] doSomething----:<NSThread: 0x600000e85400>{number = 1, name = main}
    

    二、GCD(利用更多的CPU内核)

    将任务(要在线程中执行的操作block)添加到队列中,并且指定执行任务的方式(异步dispatch_async,同步dispatch_sync)

    创建队列

         /**串行队列*/
        dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
         /**并发队列*/
        dispatch_queue_t queue1 = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
        
      /**同步执行任务*/
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"同步执行的任务");
            
        });
        /**异步执行任务*/
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"异步执行的任务");
            
        });
        
        /**主队列*/
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            //耗时操作放在这里
    
            dispatch_async(dispatch_get_main_queue(), ^{
                //回到主线程进行UI操作
            });
        });
        /**全局并发队列(DISPATCH_QUEUE_PRIORITY_DEFAULT优先级)*/
        dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //全局并发队列的优先级
    #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 // 后台优先级
        //iOS8开始可以直接传0
        //dispatch_get_global_queue(0, 0);
    

    GCD使用

    1、串行同步

    执行完一个任务,再执行下一个任务。不开启新线程

    /** 串行同步 */
    - (void)syncSerial {
    
        NSLog(@"**************串行同步***************");
    
        //串行队列
        dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    
        //同步执行
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行同步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行同步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行同步3   %@",[NSThread currentThread]);
            }
        });
    }
    

    输出结果 顺序执行,都在主线程

    2020-04-27 14:06:27.606285+0800 demoTest[65708:2448182] 串行同步1   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.606393+0800 demoTest[65708:2448182] 串行同步1   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.606509+0800 demoTest[65708:2448182] 串行同步1   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.606626+0800 demoTest[65708:2448182] 串行同步2   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.606733+0800 demoTest[65708:2448182] 串行同步2   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.606852+0800 demoTest[65708:2448182] 串行同步2   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.607005+0800 demoTest[65708:2448182] 串行同步3   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.607235+0800 demoTest[65708:2448182] 串行同步3   <NSThread: 0x600000d8d800>{number = 1, name = main}
    2020-04-27 14:06:27.607536+0800 demoTest[65708:2448182] 串行同步3   <NSThread: 0x600000d8d800>{number = 1, name = main}
    

    2、串行异步

    开启新线程,但因为任务是串行的,所以还是按顺序执行任务。

    /** 串行异步 */
    - (void)asyncSerial {
    
        NSLog(@"**************串行异步***************");
    
        //串行队列
        dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
    
        //同步执行
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行异步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行异步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"串行异步3   %@",[NSThread currentThread]);
            }
        });
    }
    

    输出结果 顺序执行,有不同线程

    2020-04-27 14:22:00.994754+0800 demoTest[67036:2467924] **************串行异步***************
    2020-04-27 14:22:00.995037+0800 demoTest[67036:2467995] 串行异步1   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.995134+0800 demoTest[67036:2467995] 串行异步1   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.995246+0800 demoTest[67036:2467995] 串行异步1   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.995355+0800 demoTest[67036:2467995] 串行异步2   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.995595+0800 demoTest[67036:2467995] 串行异步2   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.996034+0800 demoTest[67036:2467995] 串行异步2   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.996839+0800 demoTest[67036:2467995] 串行异步3   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.998052+0800 demoTest[67036:2467995] 串行异步3   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    2020-04-27 14:22:00.998396+0800 demoTest[67036:2467995] 串行异步3   <NSThread: 0x6000038b8fc0>{number = 5, name = (null)}
    

    3、并发同步

    /** 并发同步 */
    - (void)syncConcurrent {
        NSLog(@"**************并发同步***************");
    
        // 并发队列
        dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
        // 同步执行
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发同步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发同步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发同步3   %@",[NSThread currentThread]);
            }
        });
    }
    

    输出结果 顺序执行,都在主线程

    2020-04-27 14:27:42.688831+0800 demoTest[67202:2474582] **************并发同步***************
    2020-04-27 14:27:42.688989+0800 demoTest[67202:2474582] 并发同步1   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.689098+0800 demoTest[67202:2474582] 并发同步1   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.689221+0800 demoTest[67202:2474582] 并发同步1   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.689357+0800 demoTest[67202:2474582] 并发同步2   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.689663+0800 demoTest[67202:2474582] 并发同步2   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.689883+0800 demoTest[67202:2474582] 并发同步2   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.690198+0800 demoTest[67202:2474582] 并发同步3   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.690465+0800 demoTest[67202:2474582] 并发同步3   <NSThread: 0x600000a96f80>{number = 1, name = main}
    2020-04-27 14:27:42.690882+0800 demoTest[67202:2474582] 并发同步3   <NSThread: 0x600000a96f80>{number = 1, name = main}
    

    4、并发异步

    /** 并发异步 */
    - (void)asyncConcurrent {
    
        NSLog(@"**************并发异步***************");
    
        // 并发队列
        dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
        // 同步执行
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发异步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发异步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"并发异步3   %@",[NSThread currentThread]);
            }
        });
    }
    

    输出结果 无序执行 多个线程

    2020-04-27 14:29:54.985408+0800 demoTest[67264:2477386] **************并发异步***************
    2020-04-27 14:29:54.985746+0800 demoTest[67264:2477448] 并发异步3   <NSThread: 0x60000148d200>{number = 5, name = (null)}
    2020-04-27 14:29:54.985748+0800 demoTest[67264:2477451] 并发异步1   <NSThread: 0x600001406d40>{number = 6, name = (null)}
    2020-04-27 14:29:54.985757+0800 demoTest[67264:2477445] 并发异步2   <NSThread: 0x60000148e3c0>{number = 3, name = (null)}
    2020-04-27 14:29:54.985859+0800 demoTest[67264:2477448] 并发异步3   <NSThread: 0x60000148d200>{number = 5, name = (null)}
    2020-04-27 14:29:54.985880+0800 demoTest[67264:2477451] 并发异步1   <NSThread: 0x600001406d40>{number = 6, name = (null)}
    2020-04-27 14:29:54.985890+0800 demoTest[67264:2477445] 并发异步2   <NSThread: 0x60000148e3c0>{number = 3, name = (null)}
    2020-04-27 14:29:54.985966+0800 demoTest[67264:2477448] 并发异步3   <NSThread: 0x60000148d200>{number = 5, name = (null)}
    2020-04-27 14:29:54.985982+0800 demoTest[67264:2477451] 并发异步1   <NSThread: 0x600001406d40>{number = 6, name = (null)}
    2020-04-27 14:29:54.985991+0800 demoTest[67264:2477445] 并发异步2   <NSThread: 0x60000148e3c0>{number = 3, name = (null)}
    

    5、主队列同步

    /** 主队列同步 */
    - (void)syncMain {
    
        NSLog(@"**************主队列同步,放到主线程会死锁***************");
    
        // 主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列同步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列同步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_sync(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列同步3   %@",[NSThread currentThread]);
            }
        });
    }
    
    image.png

    输出结果

    2020-04-27 14:38:47.717201+0800 demoTest[67460:2486906] **************主队列同步,放到主线程会死锁***************
    其后崩溃
    

    原因:死锁:任务放在主线程队列中,在执行第一个同步任务开始时同时在等待第一个完成去执行第二三个,互相等待,形成死锁

    6、主队列异步

    /** 主队列异步 */
    - (void)asyncMain {
    
        NSLog(@"**************主队列异步***************");
    
        // 主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
    
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列异步1   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列异步2   %@",[NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"主队列异步3   %@",[NSThread currentThread]);
            }
        });
    }
    

    输出结果 主线程中按顺序执行

    2020-04-27 14:49:45.368320+0800 demoTest[67730:2498652] **************主队列异步***************
    2020-04-27 14:49:45.381310+0800 demoTest[67730:2498652] 主队列异步1   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.381452+0800 demoTest[67730:2498652] 主队列异步1   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.381566+0800 demoTest[67730:2498652] 主队列异步1   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.381702+0800 demoTest[67730:2498652] 主队列异步2   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.381801+0800 demoTest[67730:2498652] 主队列异步2   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.381904+0800 demoTest[67730:2498652] 主队列异步2   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.382027+0800 demoTest[67730:2498652] 主队列异步3   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.382304+0800 demoTest[67730:2498652] 主队列异步3   <NSThread: 0x600002ffd400>{number = 1, name = main}
    2020-04-27 14:49:45.382678+0800 demoTest[67730:2498652] 主队列异步3   <NSThread: 0x600002ffd400>{number = 1, name = main}
    

    GCD线程之间通讯

    如:耗时操作放在异步线程中,完成操作回到主线程进行UI的处理

     //异步
          dispatch_async(dispatch_get_global_queue(0, 0), ^{
              // 耗时操作放在这里,例如下载图片。(运用线程休眠两秒来模拟耗时操作)
              [NSThread sleepForTimeInterval:2];
              NSString *picURLStr = @"http://xxxxx";
              NSURL *picURL = [NSURL URLWithString:picURLStr];
              NSData *picData = [NSData dataWithContentsOfURL:picURL];
              UIImage *image = [UIImage imageWithData:picData];
    
              //回到主线程处理UI
              dispatch_async(dispatch_get_main_queue(), ^{
                  //在主线程上添加图片
                  self.imageView.image = image;
                   NSLog(@"主线程刷新   %@",[NSThread currentThread]);
              });
          });
    

    GCD栅栏

    dispatch_barrier_async 多个异步,需要分组先后执行(如1234异步,12必须在34前执行)

     //并发队列
      dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
            //异步执行
            dispatch_async(queue, ^{
                for (int i = 0; i < 3; i++) {
                    NSLog(@"栅栏:并发异步1   %@",[NSThread currentThread]);
                }
            });
            dispatch_async(queue, ^{
                for (int i = 0; i < 3; i++) {
                    NSLog(@"栅栏:并发异步2   %@",[NSThread currentThread]);
                }
            });
    
            dispatch_barrier_async(queue, ^{
                NSLog(@"------------barrier------------%@", [NSThread currentThread]);
                NSLog(@"******* 并发异步执行,但是34一定在12后面 *********");
            });
    
            dispatch_async(queue, ^{
                for (int i = 0; i < 3; i++) {
                    NSLog(@"栅栏:并发异步3   %@",[NSThread currentThread]);
                }
            });
            dispatch_async(queue, ^{
                for (int i = 0; i < 3; i++) {
                    NSLog(@"栅栏:并发异步4   %@",[NSThread currentThread]);
                }
            });
    

    输出结果 12始终在34前执行

    2020-04-27 15:58:23.737078+0800 demoTest[91128:2624333] 栅栏:并发异步2   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.737096+0800 demoTest[91128:2624331] 栅栏:并发异步1   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.737247+0800 demoTest[91128:2624331] 栅栏:并发异步1   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.737247+0800 demoTest[91128:2624333] 栅栏:并发异步2   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.737366+0800 demoTest[91128:2624331] 栅栏:并发异步1   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.737399+0800 demoTest[91128:2624333] 栅栏:并发异步2   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.737583+0800 demoTest[91128:2624333] ------------barrier------------<NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.738018+0800 demoTest[91128:2624333] ******* 并发异步执行,但是34一定在12后面 *********
    2020-04-27 15:58:23.738561+0800 demoTest[91128:2624331] 栅栏:并发异步4   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.738568+0800 demoTest[91128:2624333] 栅栏:并发异步3   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.739183+0800 demoTest[91128:2624331] 栅栏:并发异步4   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.745339+0800 demoTest[91128:2624331] 栅栏:并发异步4   <NSThread: 0x600001b32900>{number = 3, name = (null)}
    2020-04-27 15:58:23.745310+0800 demoTest[91128:2624333] 栅栏:并发异步3   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    2020-04-27 15:58:23.745678+0800 demoTest[91128:2624333] 栅栏:并发异步3   <NSThread: 0x600001b0f540>{number = 6, name = (null)}
    

    GCD信号量(dispatch_semaphore)

    信号量

    应该场景:要下载很多图片,并发异步进行,每个下载都会开辟一个新线程,担心线程太多cpu吃不消->信号量控制最大开辟线程数
    相关函数:
    dispatch_semaphore_create(最大信号量值)---创建信号量
    dispatch_semaphore_wait(信号量,等待时间)---等待降低信号量
    dispatch_semaphore_signal(信号量)---提高信号量

    开5个线程,控制每次最大并发2个
    -(void)dispatchSignal{
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
        dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        //任务1
        dispatch_async(quene, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"任务 1------%@",[NSThread currentThread]);
            sleep(1);
            NSLog(@"完成任务 1");
            dispatch_semaphore_signal(semaphore);
        });
        //任务2
        dispatch_async(quene, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"任务 2-----%@",[NSThread currentThread]);
            sleep(1);
            NSLog(@"完成任务 2");
            dispatch_semaphore_signal(semaphore);
        });
        //任务3
        dispatch_async(quene, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"任务 3------%@",[NSThread currentThread]);
            sleep(1);
            NSLog(@"完成任务 3");
            dispatch_semaphore_signal(semaphore);
        });
        
        //任务4
        dispatch_async(quene, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"任务 4------%@",[NSThread currentThread]);
            sleep(1);
            NSLog(@"完成任务 4");
            dispatch_semaphore_signal(semaphore);
        });
        
        //任务5
        dispatch_async(quene, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"任务 5------%@",[NSThread currentThread]);
            sleep(1);
            NSLog(@"完成任务 5");
            dispatch_semaphore_signal(semaphore);
        });
    }
    

    运行结果:21完成->43完成->5完成

    2020-05-12 10:45:16.586423+0800 demoTest[20281:3628981] 任务 1------<NSThread: 0x600003a2ed80>{number = 4, name = (null)}
    2020-05-12 10:45:16.586452+0800 demoTest[20281:3628983] 任务 2-----<NSThread: 0x600003a35340>{number = 5, name = (null)}
    2020-05-12 10:45:17.589435+0800 demoTest[20281:3628983] 完成任务 2
    2020-05-12 10:45:17.589435+0800 demoTest[20281:3628981] 完成任务 1
    2020-05-12 10:45:17.589787+0800 demoTest[20281:3628980] 任务 3------<NSThread: 0x600003a25800>{number = 3, name = (null)}
    2020-05-12 10:45:17.589811+0800 demoTest[20281:3628982] 任务 4------<NSThread: 0x600003a3b980>{number = 6, name = (null)}
    2020-05-12 10:45:18.590611+0800 demoTest[20281:3628982] 完成任务 4
    2020-05-12 10:45:18.590611+0800 demoTest[20281:3628980] 完成任务 3
    2020-05-12 10:45:18.590897+0800 demoTest[20281:3628987] 任务 5------<NSThread: 0x600003a3ea80>{number = 7, name = (null)}
    2020-05-12 10:45:19.592798+0800 demoTest[20281:3628987] 完成任务 5
    

    GCD 延时 dispatch_after

     NSLog(@"主线程   %@",[NSThread currentThread]);
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            // 5秒后异步执行
            NSLog(@"已等待5秒!");
        });
    

    输出结果

    2020-04-27 16:14:15.858859+0800 demoTest[91563:2642364] 主线程   <NSThread: 0x600003851400>{number = 1, name = main}
    2020-04-27 16:14:20.858928+0800 demoTest[91563:2642364] 已等待5秒!
    

    GCD 写单例

    + (instancetype)sharedInstance {
      static id sharedInstance;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        sharedInstance = [self new];
      });
      return sharedInstance;
    }
    

    GCD队列组

    - (void)gcdGroup {
        dispatch_group_t group =  dispatch_group_create();
    
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"队列组1:有一个耗时操作完成!");
        });
    
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"队列组2:有一个耗时操作完成!");
        });
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"前面的耗时操作都完成了,回到主线程进行相关操作");
        });
    }
    

    输出结果

    2020-04-27 16:35:37.606858+0800 demoTest[92908:2667964] 队列组2:有一个耗时操作完成!
    2020-04-27 16:35:37.606856+0800 demoTest[92908:2667965] 队列组1:有一个耗时操作完成!
    2020-04-27 16:35:37.612304+0800 demoTest[92908:2667933] 前面的耗时操作都完成了,回到主线程进行相关操作
    

    三、NSOperation(基于GCD)

    NSOperation简图

    三种创建

    - (void)testOperation {
    /** NSOperation三种创建方式 */
       ### //NSInvocationOperation
        NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
        [invocationOperation start];
       ### //NSBlockOperation
       NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"NSBlockOperation运用addExecutionBlock主任务========%@", [NSThread currentThread]);
        }];
        [blockOperation start];
        
     ###   //NSOperation
        NSOperation *operation = [[NSOperation alloc] init];
        [operation start];
        for (int i = 0; i < 3; i++) {
            NSLog(@"NSOperation======%@",[NSThread currentThread]);
        }
    }
    
    - (void)invocationOperation {
        NSLog(@"NSInvocationOperation包含的任务,没有加入队列========%@", [NSThread currentThread]);
    }
    

    执行结果如下,可以看出:都在主线程执行,没有开启新线程。

    2020-04-27 17:45:49.922770+0800 demoTest[94570:2741408] NSInvocationOperation包含的任务,没有加入队列========<NSThread: 0x600002a2a940>{number = 1, name = main}
    2020-04-27 17:45:49.923038+0800 demoTest[94570:2741408] NSBlockOperation运用addExecutionBlock主任务========<NSThread: 0x600002a2a940>{number = 1, name = main}
    2020-04-27 17:45:49.923267+0800 demoTest[94570:2741408] NSOperation======<NSThread: 0x600002a2a940>{number = 1, name = main}
    2020-04-27 17:45:49.923374+0800 demoTest[94570:2741408] NSOperation======<NSThread: 0x600002a2a940>{number = 1, name = main}
    2020-04-27 17:45:49.923463+0800 demoTest[94570:2741408] NSOperation======<NSThread: 0x600002a2a940>{number = 1, name = main}
    

    NSBlockOperation 使用addExecutionBlock:实现多线程

    - (void)testNSBlockOperationExecution {
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"NSBlockOperation运用addExecutionBlock主任务========%@", [NSThread currentThread]);
        }];
    
        [blockOperation addExecutionBlock:^{
            NSLog(@"NSBlockOperation运用addExecutionBlock方法添加任务1========%@", [NSThread currentThread]);
        }];
        [blockOperation addExecutionBlock:^{
            NSLog(@"NSBlockOperation运用addExecutionBlock方法添加任务2========%@", [NSThread currentThread]);
        }];
        [blockOperation addExecutionBlock:^{
            NSLog(@"NSBlockOperation运用addExecutionBlock方法添加任务3========%@", [NSThread currentThread]);
        }];
        [blockOperation start];
    }
    

    输出结果blockOperationWithBlock在主线程,其余在子线程

    2020-04-27 17:51:14.872756+0800 demoTest[94709:2748038] NSBlockOperation运用addExecutionBlock主任务========<NSThread: 0x6000009f2940>{number = 1, name = main}
    2020-04-27 17:51:14.872757+0800 demoTest[94709:2748104] NSBlockOperation运用addExecutionBlock方法添加任务2========<NSThread: 0x6000009b3380>{number = 3, name = (null)}
    2020-04-27 17:51:14.872772+0800 demoTest[94709:2748106] NSBlockOperation运用addExecutionBlock方法添加任务3========<NSThread: 0x60000098d300>{number = 6, name = (null)}
    2020-04-27 17:51:14.872763+0800 demoTest[94709:2748107] NSBlockOperation运用addExecutionBlock方法添加任务1========<NSThread: 0x6000009b3700>{number = 4, name = (null)}
    

    NSOperationQueue队列

    两种队列:主队列、其他队列(串行和并发)

    队列创建

    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    

    队列中添加任务

    - (void)testOperationQueue {
        //创建队列,默认并发
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        //创建操作,NSInvocationOperation
        NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperationAddOperation) object:nil];
        //创建操作,NSBlockOperation
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"blockOperation添加到队列======%@", [NSThread currentThread]);
            }
        }];
        [queue addOperation:invocationOperation];
        [queue addOperation:blockOperation];
    }
    - (void)invocationOperationAddOperation {
        NSLog(@"invocationOperation添加到队列====%@", [NSThread currentThread]);
    }
    

    输出结果:任务都是在子线程执行的,开启了新线程!

    2020-04-27 18:14:14.851880+0800 demoTest[95274:2774063] blockOperation添加到队列======<NSThread: 0x6000037f4b00>{number = 4, name = (null)}
    2020-04-27 18:14:14.851890+0800 demoTest[95274:2774062] invocationOperation添加到队列====<NSThread: 0x6000037afa40>{number = 5, name = (null)}
    2020-04-27 18:14:14.852026+0800 demoTest[95274:2774063] blockOperation添加到队列======<NSThread: 0x6000037f4b00>{number = 4, name = (null)}
    2020-04-27 18:14:14.852286+0800 demoTest[95274:2774063] blockOperation添加到队列======<NSThread: 0x6000037f4b00>{number = 4, name = (null)}
    

    NSOperationQueue 的 maxConcurrentOperationCount属性

    - (void)testMaxConcurrentOperationCount {
        // 创建队列,默认并发
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //    // 最大并发数为1,串行
    //    queue.maxConcurrentOperationCount = 1;
    
    //    // 最大并发数为2,并发
        queue.maxConcurrentOperationCount = 2;
    
    
        // 添加操作到队列
        [queue addOperationWithBlock:^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"队列1======%@", [NSThread currentThread]);
            }
        }];
        // 添加操作到队列
        [queue addOperationWithBlock:^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"队列2======%@", [NSThread currentThread]);
            }
        }];
    
        // 添加操作到队列
        [queue addOperationWithBlock:^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"队列3======%@", [NSThread currentThread]);
            }
        }];
    }
    

    maxConcurrentOperationCount 不设置或者设置为1时

    输出结果表明:开启了线程,任务是顺序执行,实现了串行

    2020-04-27 18:27:41.921078+0800 demoTest[95709:2791570] 队列1======<NSThread: 0x6000015f2140>{number = 4, name = (null)}
    2020-04-27 18:27:41.921215+0800 demoTest[95709:2791570] 队列1======<NSThread: 0x6000015f2140>{number = 4, name = (null)}
    2020-04-27 18:27:41.921325+0800 demoTest[95709:2791570] 队列1======<NSThread: 0x6000015f2140>{number = 4, name = (null)}
    2020-04-27 18:27:41.921502+0800 demoTest[95709:2791567] 队列2======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    2020-04-27 18:27:41.921613+0800 demoTest[95709:2791567] 队列2======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    2020-04-27 18:27:41.921908+0800 demoTest[95709:2791567] 队列2======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    2020-04-27 18:27:41.922299+0800 demoTest[95709:2791567] 队列3======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    2020-04-27 18:27:41.922697+0800 demoTest[95709:2791567] 队列3======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    2020-04-27 18:27:41.923262+0800 demoTest[95709:2791567] 队列3======<NSThread: 0x6000015bc300>{number = 3, name = (null)}
    

    输出结果 最大并发2个时,实现了并发,先执行先添加的前两个再执行最后一个

    2020-04-27 18:25:07.275075+0800 demoTest[95610:2788113] 队列2======<NSThread: 0x6000003ce880>{number = 4, name = (null)}
    2020-04-27 18:25:07.275123+0800 demoTest[95610:2788112] 队列1======<NSThread: 0x6000003ff380>{number = 6, name = (null)}
    2020-04-27 18:25:07.275210+0800 demoTest[95610:2788113] 队列2======<NSThread: 0x6000003ce880>{number = 4, name = (null)}
    2020-04-27 18:25:07.275241+0800 demoTest[95610:2788112] 队列1======<NSThread: 0x6000003ff380>{number = 6, name = (null)}
    2020-04-27 18:25:07.275329+0800 demoTest[95610:2788113] 队列2======<NSThread: 0x6000003ce880>{number = 4, name = (null)}
    2020-04-27 18:25:07.275339+0800 demoTest[95610:2788112] 队列1======<NSThread: 0x6000003ff380>{number = 6, name = (null)}
    2020-04-27 18:25:07.275550+0800 demoTest[95610:2788110] 队列3======<NSThread: 0x6000003c5ec0>{number = 3, name = (null)}
    2020-04-27 18:25:07.275892+0800 demoTest[95610:2788110] 队列3======<NSThread: 0x6000003c5ec0>{number = 3, name = (null)}
    2020-04-27 18:25:07.276664+0800 demoTest[95610:2788110] 队列3======<NSThread: 0x6000003c5ec0>{number = 3, name = (null)}
    

    操作依赖 addDependency

    - (void)testAddDependency {
        // 并发队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 操作1
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 3; i++) {
                NSLog(@"operation1======%@", [NSThread  currentThread]);
            }
        }];
    
        // 操作2
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"****operation2依赖于operation1,只有当operation1执行完毕,operation2才会执行****");
            for (int i = 0; i < 3; i++) {
                NSLog(@"operation2======%@", [NSThread  currentThread]);
            }
        }];
    
        //使操作2依赖于操作1
        [operation2 addDependency:operation1];
        // 把操作加入队列
        [queue addOperation:operation1];
        [queue addOperation:operation2];
    }
    

    输出结果

    2020-04-27 18:39:47.699039+0800 demoTest[96073:2807169] operation1======<NSThread: 0x6000023ddf40>{number = 5, name = (null)}
    2020-04-27 18:39:47.699234+0800 demoTest[96073:2807169] operation1======<NSThread: 0x6000023ddf40>{number = 5, name = (null)}
    2020-04-27 18:39:47.699351+0800 demoTest[96073:2807169] operation1======<NSThread: 0x6000023ddf40>{number = 5, name = (null)}
    2020-04-27 18:39:47.699625+0800 demoTest[96073:2807170] ****operation2依赖于operation1,只有当operation1执行完毕,operation2才会执行****
    2020-04-27 18:39:47.699810+0800 demoTest[96073:2807170] operation2======<NSThread: 0x600002312a00>{number = 4, name = (null)}
    2020-04-27 18:39:47.700186+0800 demoTest[96073:2807170] operation2======<NSThread: 0x600002312a00>{number = 4, name = (null)}
    2020-04-27 18:39:47.701139+0800 demoTest[96073:2807170] operation2======<NSThread: 0x600002312a00>{number = 4, name = (null)}
    

    其他操作

    //取消
    - (void)cancelAllOperations
    - (void)cancel
    // 暂停队列
    [queue setSuspended:YES];
    //判断队列是否暂停
    - (BOOL)isSuspended
    

    参考链接:http://www.cocoachina.com/articles/19769

    相关文章

      网友评论

          本文标题:iOS 多线程详解

          本文链接:https://www.haomeiwen.com/subject/ivgewhtx.html