iOS 多线程

2019-07-17  本文已影响0人  NextStepPeng

iOS使用线程的方式

  1. pthread
  2. NSThread
  3. GCD
  4. NSOperation

NSThread线程的创建与启动

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
 [thread start];
NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
[self performSelectorInBackground:@selector(run) withObject:nil];

NSThread线程相关方法

[NSThread currentThread];
//获取主线程
[NSThread mainThread];

[NSThread isMainThread];
[[NSThread currentThread] setName:@"设置线程名称"];
 [[NSThread currentThread] start];
//[NSThread sleepUntilDate:[]]
    [NSThread sleepForTimeInterval:2];

NSThread线程间通信

self performSelectorOnMainThread:<#(nonnull SEL)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>
self performSelector:<#(nonnull SEL)#> onThread:<#(nonnull NSThread *)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
//在子线程下载图片
- (void)downloadImage{
    NSURL *imageUrl = [NSURL URLWithString:@"图片地址"];
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    UIImage *image = [UIImage imageWithData:imageData];
    //在主线程将图片显示
    [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:image waitUntilDone:true];
}


- (void)refreshOnMainThread:(UIImage *) image {
    UIImageView *imageV = [[UIImageView alloc] initWithImage:image];
}

NSThread线程安全

- (void)myMethod:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}
- (NSLock *)lock
{
    if (!_lock)
    {
        _lock = [[NSLock alloc] init];
    }
    
    return _lock;
}
[self.lock lock];
    self->_myVTKPolyData->SetPoints(m_Points);
    self->_myVTKPolyData->SetLines(lines);
    self->_myVTKPolyData->GetPointData()->SetScalars(colors);
    [self.lock unlock];

-dispatch_semaphore 利用信号量控制(dispatch_semaphore_t sema = dispatch_semaphore_create(1);)

- (void)initTicketStatusSafe{
    semaphoreLock = dispatch_semaphore_create(1); //一次只有一个
    self.ticketSurplusCount = 50;
    //代表售卖窗口1
    dispatch_queue_t queue1 = dispatch_queue_create("peng1", DISPATCH_QUEUE_SERIAL);
    
    //代表售卖窗口2
    dispatch_queue_t queue2 = dispatch_queue_create("peng2", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
    
    
}

- (void)saleTicketSafe {
    while (1) {
        //如果还有票,继续售卖
        //        @synchronized (self) {
        
        dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {
            self.ticketSurplusCount --;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
            [NSThread sleepForTimeInterval:0.5];
        }
        //如果已卖完,关闭售票窗口
        else {
            NSLog(@"所有火车票均已售完");
            dispatch_semaphore_signal(semaphoreLock);
            break;
        }
        //        }
        
        dispatch_semaphore_signal(semaphoreLock);
    }
}

既然讲到了GCD信号量,就直接切入GCD多线程,GCD还是非常实用

GCD

队列(Dispatch Queue):这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表。采用FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。

GCD的使用步骤

GCD使用步骤只有两步
1、创建一个队列(串型队列或者并发队列)
备注:主队列是一个特殊的串队列

    //串型队列
    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
    //并型队列
    dispatch_queue_t queueC = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

2、将任务追加到任务的队列 中去,然后系统就会根据任务类型执行任务(同步执行或者异步执行)

    dispatch_async(queue, ^{
        // 异步追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_async(queue, ^{
        // 异步追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_sync(queue, ^{
        // 同步追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });

组合

image.png

注意,在主队列中 异步是不会开启新线程执行

dispatch_queue_t queue = dispatch_get_main_queue();
    //并型队列
    //dispatch_queue_t queueC = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
    
    
    dispatch_async(queue, ^{
        // 异步追加任务1
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_async(queue, ^{
        // 异步追加任务2
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    dispatch_async(queue, ^{
        // 异步追加任务3
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
        }
    });
    
    NSLog(@"syncConcurrent---end");
//打印
currentThread---<NSThread: 0x600003b2a940>{number = 1, name = main}
syncConcurrent---begin
syncConcurrent---end
1---<NSThread: 0x600003b2a940>{number = 1, name = main}
1---<NSThread: 0x600003b2a940>{number = 1, name = main}
2---<NSThread: 0x600003b2a940>{number = 1, name = main}
2---<NSThread: 0x600003b2a940>{number = 1, name = main}
3---<NSThread: 0x600003b2a940>{number = 1, name = main}
3---<NSThread: 0x600003b2a940>{number = 1, name = main}

GCD 线程间的通信

- (void)GCDCommunication{
    //获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //获取主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
       //异步追加任务
        for (int i = 0; i < 2; i++){
            [NSThread sleepForTimeInterval:2];
            //打印当前线程
            NSLog(@"1-----%@",[NSThread currentThread]);
        }
        
        //回到主线程
        dispatch_async(mainQueue, ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2----%@",[NSThread currentThread]);
        });
    });
}
//打印
1-----<NSThread: 0x6000021bea80>{number = 3, name = (null)}
1-----<NSThread: 0x6000021bea80>{number = 3, name = (null)}
 2----<NSThread: 0x6000021b1400>{number = 1, name = main}

GCD的其它方法

GCD栅栏方法: dispatch_barrier_async

使用场景:有时我们需要异步执行两组任务,而且第一组的任务执行完之后,才能开始执行第二组任务,这样我们就需要一个一个相当于“栅栏”一样的一个方法将两组异步执行任务分割气啦,这个时候需要用到dispatch_barrier_async方法在两个任务组将形成栅栏

- (void)barrier{
    
    dispatch_queue_t queue = dispatch_queue_create("peng", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        //异步追加任务1
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1----%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        //异步追加任务2
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2----%@",[NSThread currentThread]);
        }
    });
    
    //dispatch_barrier_sync 也可以 只是会切换到调用线程  主线程调用就是 main
    
    dispatch_barrier_async(queue, ^{
        //追加任务barrier
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"barrier----%@",[NSThread currentThread]);
        }
    });
    
    
    dispatch_async(queue, ^{
        //异步追加任务3
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3----%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        //异步追加任务4
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"4----%@",[NSThread currentThread]);
        }
    });
}
2019-07-17 15:03:33.907484+0800 YBStockChartView[1988:60887] 1----<NSThread: 0x600001476380>{number = 4, name = (null)}
2019-07-17 15:03:33.907484+0800 YBStockChartView[1988:60889] 2----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:35.910472+0800 YBStockChartView[1988:60887] 1----<NSThread: 0x600001476380>{number = 4, name = (null)}
2019-07-17 15:03:35.910479+0800 YBStockChartView[1988:60889] 2----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:37.914415+0800 YBStockChartView[1988:60889] barrier----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:39.915950+0800 YBStockChartView[1988:60889] barrier----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:41.920864+0800 YBStockChartView[1988:60889] 3----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:41.920869+0800 YBStockChartView[1988:60887] 4----<NSThread: 0x600001476380>{number = 4, name = (null)}
2019-07-17 15:03:43.923980+0800 YBStockChartView[1988:60889] 3----<NSThread: 0x600001400b80>{number = 3, name = (null)}
2019-07-17 15:03:43.924004+0800 YBStockChartView[1988:60887] 4----<NSThread: 0x600001476380>{number = 4, name = (null)}

GCD延时操作

- (void)after{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        //2秒后异步追加到主队列执行
        NSLog(@"after-----%@",[NSThread currentThread]);
    });
}

GCD 只有执行一次性:dispatch_once

在整个程序运行过程中只执行一次

- (void)once {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //只执行一次
        NSLog(@"只执行一次");
    });
}

GCD快速迭代方法:dispatch_apply

与FOR 循环区别,for 循环 顺序遍历 ,而 dispatch_apply 不是

- (void)dispatch_apply{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    NSLog(@"apply-- begin");
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd----%@",index,[NSThread currentThread]);
    });
    
    NSLog(@"apply---end");
}
2019-07-17 15:25:12.435116+0800 YBStockChartView[2352:77865] apply-- begin
2019-07-17 15:25:12.435942+0800 YBStockChartView[2352:77901] 4----<NSThread: 0x6000017a8980>{number = 5, name = (null)}
2019-07-17 15:25:12.435946+0800 YBStockChartView[2352:77900] 2----<NSThread: 0x6000017bfe80>{number = 4, name = (null)}
2019-07-17 15:25:12.435948+0800 YBStockChartView[2352:77904] 1----<NSThread: 0x6000017c9b00>{number = 3, name = (null)}
2019-07-17 15:25:12.435948+0800 YBStockChartView[2352:77865] 0----<NSThread: 0x6000017f1400>{number = 1, name = main}
2019-07-17 15:25:12.435955+0800 YBStockChartView[2352:77903] 3----<NSThread: 0x6000017c9a40>{number = 6, name = (null)}
2019-07-17 15:25:12.435965+0800 YBStockChartView[2352:77902] 5----<NSThread: 0x6000017a0b40>{number = 7, name = (null)}
2019-07-17 15:25:12.436115+0800 YBStockChartView[2352:77865] apply---end

GCD 队列组 dispatch_group

- (void)dispatch_group{
    dispatch_group_t gruop = dispatch_group_create();
    
    
    dispatch_group_async(gruop, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //追加耗时任务
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1====%@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_async(gruop, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //追加耗时任务
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2====%@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_notify(gruop, dispatch_get_main_queue(), ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3====%@",[NSThread currentThread]);
        }
        NSLog(@"group--end");
    });
}

2019-07-17 15:39:32.459319+0800 YBStockChartView[2552:87029] 2====<NSThread: 0x600002ee4780>{number = 3, name = (null)}
2019-07-17 15:39:32.459320+0800 YBStockChartView[2552:87028] 1====<NSThread: 0x600002ed8200>{number = 4, name = (null)}
2019-07-17 15:39:34.464453+0800 YBStockChartView[2552:87028] 1====<NSThread: 0x600002ed8200>{number = 4, name = (null)}
2019-07-17 15:39:34.464480+0800 YBStockChartView[2552:87029] 2====<NSThread: 0x600002ee4780>{number = 3, name = (null)}
2019-07-17 15:39:36.465933+0800 YBStockChartView[2552:86994] 3====<NSThread: 0x600002eba940>{number = 1, name = main}
2019-07-17 15:39:38.466517+0800 YBStockChartView[2552:86994] 3====<NSThread: 0x600002eba940>{number = 1, name = main}
2019-07-17 15:39:38.466685+0800 YBStockChartView[2552:86994] group--end

GCD dispatch_group_wait

暂停当前线程(阻塞),等待指定的group中的任务执行完成后,才会往下执行

- (void)groupWait{
    NSLog(@"currentThread====%@",[NSThread currentThread]);
    NSLog(@"group--begin");
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       //追加
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1=====%@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //追加
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2=====%@",[NSThread currentThread]);
        }
    });
    
    // 等待上面的任务全部完成后,会往下继续执行(会阻塞当前线程)
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"group---end");
}

GCD dispatch_group_enter、dispatch_group_leave

- (void)gruopEnterAndLeave{
    NSLog(@"currentThread===%@",[NSThread currentThread]);
    NSLog(@"group--begin");
    
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1==-%@",[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2==-%@",[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        for (int i = 0; i < 2; i ++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3==-%@",[NSThread currentThread]);
        }
        NSLog(@"group====end");
    });
    
  
}
2019-07-17 16:07:42.775761+0800 YBStockChartView[2954:104854] currentThread===<NSThread: 0x600003cb6940>{number = 1, name = main}
2019-07-17 16:07:42.775845+0800 YBStockChartView[2954:104854] group--begin
2019-07-17 16:07:44.778363+0800 YBStockChartView[2954:104888] 2==-<NSThread: 0x600003cfa480>{number = 3, name = (null)}
2019-07-17 16:07:44.778373+0800 YBStockChartView[2954:104887] 1==-<NSThread: 0x600003cdcb00>{number = 4, name = (null)}
2019-07-17 16:07:46.783729+0800 YBStockChartView[2954:104887] 1==-<NSThread: 0x600003cdcb00>{number = 4, name = (null)}
2019-07-17 16:07:46.783748+0800 YBStockChartView[2954:104888] 2==-<NSThread: 0x600003cfa480>{number = 3, name = (null)}
2019-07-17 16:07:48.784472+0800 YBStockChartView[2954:104854] 3==-<NSThread: 0x600003cb6940>{number = 1, name = main}
2019-07-17 16:07:50.785241+0800 YBStockChartView[2954:104854] 3==-<NSThread: 0x600003cb6940>{number = 1, name = main}
2019-07-17 16:07:50.785515+0800 YBStockChartView[2954:104854] group====end

GCD信号量 dispatch_semaphone

将异步线程转换为同步线程 还可以利用信号量保证线程安全

- (void)semaphoneSync{
    NSLog(@"currentThread===%@",[NSThread currentThread]);
    NSLog(@"semaphone--begin");
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_semaphore_t semaphone = dispatch_semaphore_create(0);
//创建一个 Semaphore 并初始化信号的总量
    
    __block int number = 0;
    dispatch_async(queue, ^{
       //追加任务
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1======%@",[NSThread currentThread]);
        
        number =100;
        //发送一个信号,让信号总量加 1
        dispatch_semaphore_signal(semaphone);
        
    });
    //dispatch_semaphore_signal(semaphone);
//可以使总信号量减 1,信号总量小于 1 时就会一直等待(阻塞所在线程),否则就可以正常执行
    dispatch_semaphore_wait(semaphone, DISPATCH_TIME_FOREVER);
    
    NSLog(@"semaphore---end,num == %d",number);
}

2019-07-17 16:33:22.483822+0800 YBStockChartView[3373:125495] currentThread===<NSThread: 0x6000029fe940>{number = 1, name = main}
2019-07-17 16:33:22.483902+0800 YBStockChartView[3373:125495] semaphone--begin
2019-07-17 16:33:24.484306+0800 YBStockChartView[3373:125556] 1======<NSThread: 0x6000029a6a00>{number = 3, name = (null)}
2019-07-17 16:33:24.484620+0800 YBStockChartView[3373:125495] semaphore---end,num == 100

NSOperation

是苹果提供给开发者一套多线程解决方案,实际上基于GCD更高一层的封装,完全面向对象。但比GCD 更简单易用、代码可读性也更高
1、可以使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled。
2、设定操作执行的优先级
3、可以很方便的取消一个操作的执行

NSOperation、NSOperationQueue 操作和操作队列,

可以结合GCD的任务和任务队列理解

NSOperation、NSOperationQueue 使用步骤

NSOperation需要配合NSOperationQueue来实现多线程。默认情况下
NSOperation 单独使用时系统同步执行操作,配合NSOperationQueue 能更好的实现异步执行

分为三步
1、创建操作:先将需要执行的操作封装到一个NSOperation对象中
2、创建队列:创建NSOperationQueue 对象
3、将操作加入到队列中:将NSOperation对象添加到NSOperatinoQueue对象中

然后系统就会自动将NSOperationQueue 中的NSOperation 取出来,在新线程中执行操作。

NSOperation 和 NSOperationQueue 基本使用

创建

NSOperation是个抽象类,需要使用他的子类来封装操作,

使用子类NSInvocationOperation
- (void)useInvocationOperation{
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
    [op start];
}

-(void)task1{
    for (int i = 0; i < 5; i++) {
        NSLog(@"1---%@",[NSThread currentThread]); //打印当前线程
    }
}
2019-07-17 17:05:52.389871+0800 YBStockChartView[3820:146376] 1---<NSThread: 0x60000151e940>{number = 1, name = main}
2019-07-17 17:05:52.389995+0800 YBStockChartView[3820:146376] 1---<NSThread: 0x60000151e940>{number = 1, name = main}
2019-07-17 17:05:52.390056+0800 YBStockChartView[3820:146376] 1---<NSThread: 0x60000151e940>{number = 1, name = main}
2019-07-17 17:05:52.390132+0800 YBStockChartView[3820:146376] 1---<NSThread: 0x60000151e940>{number = 1, name = main}
2019-07-17 17:05:52.390232+0800 YBStockChartView[3820:146376] 1---<NSThread: 0x60000151e940>{number = 1, name = main}

上面打印可以看出,在没有使用NSOperationQueue,在主线程中单独使用子类 NSInvocationOperation 执行一个操作的情况下,操作是在当前线程执行的,并没有开启新线程

使用NSBlockOperation
- (void)useBlockOperation{
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"1---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op start];
}

并没有开新线程,但是 NSBlockOperation 的addExecutionBlock 可以在开启新线程

- (void)useBlockOperation{
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"1---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op addExecutionBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"2---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op addExecutionBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"3---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op addExecutionBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"4---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op addExecutionBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"5---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    
    [op start];
}
2019-07-17 17:13:33.847155+0800 YBStockChartView[3939:152105] 2---<NSThread: 0x600000794000>{number = 3, name = (null)}
2019-07-17 17:13:33.847161+0800 YBStockChartView[3939:152106] 5---<NSThread: 0x600000794040>{number = 6, name = (null)}
2019-07-17 17:13:33.847160+0800 YBStockChartView[3939:152071] 1---<NSThread: 0x6000007fe900>{number = 1, name = main}
2019-07-17 17:13:33.847160+0800 YBStockChartView[3939:152104] 3---<NSThread: 0x6000007a87c0>{number = 4, name = (null)}
2019-07-17 17:13:33.847162+0800 YBStockChartView[3939:152103] 4---<NSThread: 0x6000007b2c40>{number = 5, name = (null)}
2019-07-17 17:13:33.847288+0800 YBStockChartView[3939:152105] 2---<NSThread: 0x600000794000>{number = 3, name = (null)}
2019-07-17 17:13:33.847289+0800 YBStockChartView[3939:152104] 3---<NSThread: 0x6000007a87c0>{number = 4, name = (null)}
2019-07-17 17:13:33.847289+0800 YBStockChartView[3939:152071] 1---<NSThread: 0x6000007fe900>{number = 1, name = main}
2019-07-17 17:13:33.847290+0800 YBStockChartView[3939:152103] 4---<NSThread: 0x6000007b2c40>{number = 5, name = (null)}
2019-07-17 17:13:33.847296+0800 YBStockChartView[3939:152106] 5---<NSThread: 0x600000794040>{number = 6, name = (null)}
2019-07-17 17:13:33.847347+0800 YBStockChartView[3939:152105] 2---<NSThread: 0x600000794000>{number = 3, name = (null)}
2019-07-17 17:13:33.847372+0800 YBStockChartView[3939:152104] 3---<NSThread: 0x6000007a87c0>{number = 4, name = (null)}
2019-07-17 17:13:33.847430+0800 YBStockChartView[3939:152071] 1---<NSThread: 0x6000007fe900>{number = 1, name = main}
2019-07-17 17:13:33.847596+0800 YBStockChartView[3939:152103] 4---<NSThread: 0x6000007b2c40>{number = 5, name = (null)}
2019-07-17 17:13:33.847715+0800 YBStockChartView[3939:152106] 5---<NSThread: 0x600000794040>{number = 6, name = (null)}
2019-07-17 17:13:33.847797+0800 YBStockChartView[3939:152105] 2---<NSThread: 0x600000794000>{number = 3, name = (null)}
2019-07-17 17:13:33.847913+0800 YBStockChartView[3939:152104] 3---<NSThread: 0x6000007a87c0>{number = 4, name = (null)}
2019-07-17 17:13:33.847990+0800 YBStockChartView[3939:152071] 1---<NSThread: 0x6000007fe900>{number = 1, name = main}
2019-07-17 17:13:33.848107+0800 YBStockChartView[3939:152103] 4---<NSThread: 0x6000007b2c40>{number = 5, name = (null)}
2019-07-17 17:13:33.848199+0800 YBStockChartView[3939:152106] 5---<NSThread: 0x600000794040>{number = 6, name = (null)}

一般情况下,如果一个NSBlockOperation对象封装了多个操作,是否开启新线程,取决操作的个数,操作个数多就会开启多线程。具体个数有系统决定

使用自定义继承自NSOperatrion的子类 重写main方法
//NSOperation
- (void)main{
    if (!self.isCancelled) {
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"PengOperation====%@", [NSThread currentThread]);
            
        }
    }
}

创建队列 NSOperationQueue

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

将操作加入到队列中

- (void)addOprationToQueue{
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //创建操作
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil];
    
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"op3---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    [op3 addExecutionBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"other==op3---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    
    [queue addOperation:op];
    [queue addOperation:op2];
    [queue addOperation:op3];
    
}

- (void)addOperationWithBlock:(void (^)(void))block;

无需先创建操作,在block中添加操作,直接将包含block加入到队列中

- (void)addOperationWithBlockToQueue{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 4; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1----%@",[NSThread currentThread]);
        }
    }];
    
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 4; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2----%@",[NSThread currentThread]);
        }
    }];
    
    
}
2019-07-17 17:39:52.279263+0800 YBStockChartView[4380:172928] 2----<NSThread: 0x6000012da340>{number = 4, name = (null)}
2019-07-17 17:39:52.279275+0800 YBStockChartView[4380:172926] 1----<NSThread: 0x6000012cb500>{number = 3, name = (null)}
2019-07-17 17:39:54.279991+0800 YBStockChartView[4380:172926] 1----<NSThread: 0x6000012cb500>{number = 3, name = (null)}
2019-07-17 17:39:54.279997+0800 YBStockChartView[4380:172928] 2----<NSThread: 0x6000012da340>{number = 4, name = (null)}
2019-07-17 17:39:56.283783+0800 YBStockChartView[4380:172928] 2----<NSThread: 0x6000012da340>{number = 4, name = (null)}
2019-07-17 17:39:56.283804+0800 YBStockChartView[4380:172926] 1----<NSThread: 0x6000012cb500>{number = 3, name = (null)}
2019-07-17 17:39:58.285930+0800 YBStockChartView[4380:172926] 1----<NSThread: 0x6000012cb500>{number = 3, name = (null)}
2019-07-17 17:39:58.285930+0800 YBStockChartView[4380:172928] 2----<NSThread: 0x6000012da340>{number = 4, name = (null)}

NSOperatrion控制串行、并发执行---maxConcurrentOperationCount

注意:这里maxConcurrentOperationCount 控制的不是并发线程的数量,而是一个队列中同时能并发执行的最大操作数,而且一个操作也并非只能在一个线程中运行
默认情况maxConcurrentOperationCount = -1

- (void)addOperationWithBlockToQueue{
    NSLog(@"currentThread----%@",[NSThread currentThread]);
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //queue.maxConcurrentOperationCount = 1; //串行队列,切记并非只有一个线程,刻意有多个线程,但并发数最大为1
    queue.maxConcurrentOperationCount = 6;
    
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 4; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1----%@",[NSThread currentThread]);
        }
    }];
    
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 4; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2----%@",[NSThread currentThread]);
        }
    }];
    
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 4; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3----%@",[NSThread currentThread]);
        }
    }];
    
     NSLog(@"currentThread---end----%@",[NSThread currentThread]);
}

NSOperatrion 操作依赖

- (void)addDependency{
    
    //1/创建队列
    NSLog(@"currentThread----%@",[NSThread currentThread]);
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //queue.maxConcurrentOperationCount = 1; //串行队列,切记并非只有一个线程,刻意有多个线程,但并发数最大为1
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"op3---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"op4---%@",[NSThread currentThread]); //打印当前线程
        }
    }];
    
    
    [op3 addDependency:op4];
    
    [queue addOperation:op3];
    [queue addOperation:op4];
    
    NSLog(@"currentThread---end----%@",[NSThread currentThread]);
    
}
2019-07-17 18:04:28.581372+0800 YBStockChartView[4808:189453] currentThread----<NSThread: 0x600002c42940>{number = 1, name = main}
2019-07-17 18:04:28.581706+0800 YBStockChartView[4808:189453] currentThread---end----<NSThread: 0x600002c42940>{number = 1, name = main}
2019-07-17 18:04:28.581756+0800 YBStockChartView[4808:189498] op4---<NSThread: 0x600002c1b0c0>{number = 3, name = (null)}
2019-07-17 18:04:28.581834+0800 YBStockChartView[4808:189498] op4---<NSThread: 0x600002c1b0c0>{number = 3, name = (null)}
2019-07-17 18:04:28.581897+0800 YBStockChartView[4808:189498] op4---<NSThread: 0x600002c1b0c0>{number = 3, name = (null)}
2019-07-17 18:04:28.581978+0800 YBStockChartView[4808:189498] op4---<NSThread: 0x600002c1b0c0>{number = 3, name = (null)}
2019-07-17 18:04:28.582085+0800 YBStockChartView[4808:189498] op4---<NSThread: 0x600002c1b0c0>{number = 3, name = (null)}
2019-07-17 18:04:28.582262+0800 YBStockChartView[4808:189494] op3---<NSThread: 0x600002c1d240>{number = 4, name = (null)}
2019-07-17 18:04:28.582342+0800 YBStockChartView[4808:189494] op3---<NSThread: 0x600002c1d240>{number = 4, name = (null)}
2019-07-17 18:04:28.593061+0800 YBStockChartView[4808:189494] op3---<NSThread: 0x600002c1d240>{number = 4, name = (null)}
2019-07-17 18:04:28.593160+0800 YBStockChartView[4808:189494] op3---<NSThread: 0x600002c1d240>{number = 4, name = (null)}
2019-07-17 18:04:28.593247+0800 YBStockChartView[4808:189494] op3---<NSThread: 0x600002c1d240>{number = 4, name = (null)}

NSOperation 、NSOperationQueue线程间的通信

- (void)communication{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"1=====%@",[NSThread currentThread]);
        }
        
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"主线程刷新UI%@",[NSThread currentThread]);
        }];
    }];
}

2019-07-17 20:57:03.534990+0800 YBStockChartView[5714:238159] 1=====<NSThread: 0x6000008fd100>{number = 3, name = (null)}
2019-07-17 20:57:03.535153+0800 YBStockChartView[5714:238159] 1=====<NSThread: 0x6000008fd100>{number = 3, name = (null)}
2019-07-17 20:57:03.535227+0800 YBStockChartView[5714:238159] 1=====<NSThread: 0x6000008fd100>{number = 3, name = (null)}
2019-07-17 20:57:03.537354+0800 YBStockChartView[5714:238126] 主线程刷新UI<NSThread: 0x6000008aa940>{number = 1, name = main}

NSOperation 常用属性和方法

NSOperationQueue 常用属性和方法

注意:

这里的暂停和取消(包括操作的取消和队列的取消)并不代表可以将当前的操作立即取消,而是当当前的操作执行完毕之后不再执行新的操作。
暂停和取消的区别就在于:暂停操作之后还可以恢复操作,继续向下执行;而取消操作之后,所有的操作就清空了,无法再接着执行剩下的操作

上一篇下一篇

猜你喜欢

热点阅读