iOSer 的自我修养iOS专攻资源__网络专题iOS精华文章

关于iOS多线程浅析

2017-01-14  本文已影响1377人  MiracleGl

多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个执行绪,进而提升整体处理性能。 —— 维基百科


多线程的概念

同步异步(同步和异步是两种执行任务的方式。)

多线程的线程进程

多线程的方式

- (void)downloadImage
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"downloadImage %@",[NSThread currentThread]);
        
        // URL
        NSURL *URL = [NSURL URLWithString:@"http://atth.eduu.com/album/201203/12/1475134_1331559643qMzc.jpg"];
        // data
        NSData *data = [NSData dataWithContentsOfURL:URL];
        // image
        UIImage *image = [UIImage imageWithData:data];
        
        // 拿到图片对象之后,回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSLog(@"updateUI %@",[NSThread currentThread]);
            
            self.myImageView.image = image;
            [self.myImageView sizeToFit];
            [self.myScrollView setContentSize:image.size];
        });
    });
}

串行队列+同步任务

/*
 1.不开线程
 2.有序执行
*/
- (void)GCDDemo1
{
    /* 
     创建串行队列
     参数1 : 队列的标识符
     参数2 :  队列的属性,决定了队列是串行的还是并行的
     DISPATCH_QUEUE_SERIAL : 串行队列
    */
    dispatch_queue_t queue = dispatch_queue_create("GL", DISPATCH_QUEUE_SERIAL);
    
    // 循环的创建了10个同步任务,添加到队列
    for (NSInteger i = 0; i<10; i++) {
        
        // 把同步任务添加到串行队列
        dispatch_sync(queue, ^{
            NSLog(@"%zd %@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"哈哈哈");
}

串行队列+异步任务

- (void)GCDDemo2
{
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("GL", DISPATCH_QUEUE_SERIAL);
    
    for (NSInteger i = 0; i<10; i++) {
        // 把异步任务添加到串行队列
        dispatch_async(queue, ^{
            NSLog(@"%zd %@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"嘿嘿嘿");
}

并行队列+同步任务

/*
 不开线程
 有序执行
 */
- (void)GCDDemo1
{
    // 创建并行队列
    // DISPATCH_QUEUE_CONCURRENT : 并行队列
    // 并行队列只能决定"是否"可以同时调度多个任务;不能决定开不开线程
    dispatch_queue_t queue = dispatch_queue_create("GL", DISPATCH_QUEUE_CONCURRENT);
    
    for (NSInteger i = 0; i<10; i++) {
        // 把同步任务添加到并行队列
        dispatch_sync(queue, ^{
            NSLog(@"%zd %@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"哈哈哈");
}

并行队列+异步任务

/*
 开线程
 无序执行
 */
- (void)GCDDemo2
{
    // 并行队列
    dispatch_queue_t queue = dispatch_queue_create("GL", DISPATCH_QUEUE_CONCURRENT);
    
    for (NSInteger i = 0; i<10; i++) {
        
        // 把异步任务添加到并发队列
        dispatch_async(queue, ^{
            NSLog(@"%zd %@",i,[NSThread currentThread]);
        });
    }
    
    NSLog(@"嘿嘿嘿");
}
Paste_Image.png

设置最大并发数

// 队列的最大并发数的属性
// 作用 : 控制队列同时调度任务执行的个数;
// 间接控制了线程的数量;
// 注意 : 队列的最大并发数,不是线程数;

@implementation ViewController {
    
    /// 全局队列
    NSOperationQueue *_queue;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _queue = [[NSOperationQueue alloc] init];
    
    // 设置队列的最大并发数 : 至少开两个
    _queue.maxConcurrentOperationCount = 2;
}

演示

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self GCDDemo];
}

- (void)GCDDemo
{
    for (NSInteger i = 0; i<50; i++) {
        
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"%zd %@",i,[NSThread currentThread]);
        }];
        
        [_queue addOperation:op];
    }
}

执行结果:任务是两个两个的执行。

继续、暂停、取消全部
#pragma 取消全部
/*
 1.正在执行的操作无法被取消;
 2.如果非要取消正在执行的操作,需要自定义NSOperation
 3.这个取消全部的操作有一定的时间延迟
 */
- (IBAction)cancelAll:(id)sender
{
    // 移除队列里面"所有"的操作
    [_queue cancelAllOperations];
    
    NSLog(@"取消全部 %tu",_queue.operationCount);
}

#pragma 继续
- (IBAction)jixu:(id)sender
{
    // 不挂起队列,使队列继续调度任务执行
    _queue.suspended = NO;
    
    NSLog(@"继续 %tu",_queue.operationCount);
}

#pragma 暂停
/*
 1.正在执行的操作无法被暂停
 2.operationCount : 队列里面的操作个数;统计的是队列里面还没有执行完的操作;
 3.队列里面的任务一旦执行完,会从队列里面移除;
 */
- (IBAction)zanting:(id)sender
{
    // 挂起队列,使队列暂停调度任务执行
    _queue.suspended = YES;
    
    NSLog(@"暂停 %tu",_queue.operationCount);
}

将队列挂起之后,队列中的操作就不会被调度,但是正在执行的操作不受影响。operationCount:操作计数,没有执行和没有执行完的操作,都会计算在操作计数之内。注意:如果先暂停队列,再添加操作到队列,队列不会调度操作执行。所以在暂停队列之前要判断队列中有没有任务,如果没有操作就不暂停队列。

一旦调用的 cancelAllOperations方法,队列中的操作,都会被移除,正在执行的操作除外。 正在执行的操作取消不了,如果要取消,需要自定义NSOperation。 队列取消全部操作时,会有一定的时间延迟。

场景:登陆-->付费-->下载-->通知用户

准备需要执行的操作

    // 登录
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"登录 %@",[NSThread currentThread]);
    }];
    
    // 付费
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"付费 %@",[NSThread currentThread]);
    }];
    
    // 下载
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载 %@",[NSThread currentThread]);
    }];
    
    // 通知用户
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"通知用户 %@",[NSThread currentThread]);
    }];

添加依赖(核心代码)

    /*
     添加依赖关系
     1.不能在操作添加到队列之后,在建立依赖关系;因为已经晚了
     2.可以跨队列建立依赖关系
     3.不能建立循环依赖
     */
    [op2 addDependency:op1]; // 付费依赖登录
    [op3 addDependency:op2]; // 下载依赖付费
    [op4 addDependency:op3]; // 通知用户依赖下载
    
    // [op1 addDependency:op4]; // 登录依赖通知用户 : 循环依赖;会卡死
    
    // 批量把操作添加到队列
    // waitUntilFinished : 是否等待前面的异步任务执行完,在执行后面的代码
    [_queue addOperations:@[op1,op2,op3] waitUntilFinished:NO];
    
    // 一个操作不能同时添加到两个队列
    [[NSOperationQueue mainQueue] addOperation:op4];

面试题

感谢读到最后的朋友,最后请点赞支持一下,谢谢!

上一篇 下一篇

猜你喜欢

热点阅读