多线程

作者: 精神薇 | 来源:发表于2016-12-22 20:38 被阅读0次

    一、NSthread的初始化

    1.动态方法

    -(id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
    
    // 初始化线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    // 设置线程的优先级(0.0 - 1.0,1.0最高级)
    thread.threadPriority = 1;
    // 开启线程
    [thread start];
    

    参数解析:
    selector :线程执行的方法,这个selector最多只能接收一个参数
    target :selector消息发送的对象
    argument : 传给selector的唯一参数,也可以是nil

    2.静态方法

    + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;  
    
    [NSThread detachNewThreadSelector:@selector(downloagImage:) toTarget:self withObject:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
    -(void)downloagImage:(NSString*)url
    {
        NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
        UIImage *image= [[UIImage alloc] initWithData:data];
        if (image) {
           [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
       }
    }
    

    3.隐式创建线程的方法

    [self performSelectorInBackground:@selector(run) withObject:nil];  
    

    4.获取当前线程

    NSThread *current = [NSThread currentThread];  
    

    5.获取主线程

    NSThread *main = [NSThread mainThread];  
    

    6.在指定线程上执行操作

    [self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];  
    

    7.在主线程上执行操作

    [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];  
    

    8.在当前线程执行操作

    [self performSelector:@selector(run) withObject:nil];  
    

    9.优缺点

    1.优点:NSThread比其他两种多线程方案较轻量级,更直观地控制线程对象
    2.缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

    GCD

    二、GCD

    6种
    并行队列 + 同步执行(不会开启新线程)
    并行队列 + 异步执行(可同时开启多线程,任务交替执行)
    串行队列 + 同步执行(不会开启新线程)
    串行队列 + 异步执行(可同时开启多线程)
    主队列 + 同步执行 ***互等卡住不可行
    主队列 + 异步执行 ***执行完一个任务,再执行下一个任务

    // 串行队列的创建方法
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    // 并行队列的创建方法
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    // 同步执行任务创建方法
    dispatch_sync(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);    // 这里放任务代码
    });
    // 异步执行任务创建方法
    dispatch_async(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);    // 这里放任务代码
    });
    

    1.栅栏方法 dispatch_barrier_async,在执行完栅栏前面的操作之后,才执行栅栏操作,最后再执行栅栏后边的操作

    dispatch_barrier_async(queue, ^{
            NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    

    2.延时执行方法 dispatch_after

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 2秒后异步执行这里的代码...
       NSLog(@"run-----");
    });
    

    3.一次性代码(只执行一次) dispatch_once(单例)

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 只执行1次的代码(这里面默认是线程安全的)
    });
    

    4.快速迭代方法 dispatch_apply

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd------%@",index, [NSThread currentThread]);
    });
    

    5.队列组 dispatch_group

    dispatch_group_t group =  dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的异步操作都执行完毕后,回到主线程...
    });
    

    三、NSOperation

    1. 使用子类- NSInvocationOperation:

    // 1.创建NSInvocationOperation对象
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    
    // 2.调用start方法开始执行操作
    [op start];
    - (void)run
    {
        NSLog(@"------%@", [NSThread currentThread]);
    }
    

    在没有使用NSOperationQueue、单独使用NSInvocationOperation的情况下,NSInvocationOperation在主线程执行操作,并没有开启新线程

    2.使用子类- NSBlockOperation

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        // 在主线程
        NSLog(@"------%@", [NSThread currentThread]);
    }];
    [op start];
    

    在没有使用NSOperationQueue、单独使用NSBlockOperation的情况下,NSBlockOperation也是在主线程执行操作,并没有开启新线程
    但是,NSBlockOperation还提供了一个方法addExecutionBlock:,通过addExecutionBlock:就可以为NSBlockOperation添加额外的操作,这些额外的操作就会在其他线程并发执行。

    - (void)blockOperation
    {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            // 在主线程
            NSLog(@"1------%@", [NSThread currentThread]);
        }];    
    
        // 添加额外的任务(在子线程执行)
        [op addExecutionBlock:^{
            NSLog(@"2------%@", [NSThread currentThread]);
        }];
        [op addExecutionBlock:^{
            NSLog(@"3------%@", [NSThread currentThread]);
        }];
        [op addExecutionBlock:^{
            NSLog(@"4------%@", [NSThread currentThread]);
        }];
    
        [op start];
    }
    

    blockOperationWithBlock:方法中的操作是在主线程中执行的,而addExecutionBlock:方法中的操作是在其他线程中执行的

    3.将任务加入到队列中

    (1).- (void)addOperation:(NSOperation *)op;需要先创建任务,再将创建好的任务加入到创建好的队列中去

    - (void)addOperationToQueue
    {
        // 1.创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 2. 创建操作  
        // 创建NSInvocationOperation    
        NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];    
        // 创建NSBlockOperation    
        NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 2; ++i) {
                NSLog(@"1-----%@", [NSThread currentThread]);
            }
        }];
    
        // 3. 添加操作到队列中:addOperation:   
        [queue addOperation:op1]; // [op1 start]    
        [queue addOperation:op2]; // [op2 start]
    }
    
    - (void)run
    {
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    }
    

    NSInvocationOperation和NSOperationQueue结合后能够开启新线程,进行并发执行NSBlockOperation和NSOperationQueue也能够开启新线程,进行并发执行
    (2).- (void)addOperationWithBlock:(void (^)(void))block;无需先创建任务,在block中添加任务,直接将任务block加入到队列中

    - (void)addOperationWithBlockToQueue
    {
        // 1. 创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 2. 添加操作到队列中:addOperationWithBlock:
        [queue addOperationWithBlock:^{
            for (int i = 0; i < 2; ++i) {
                NSLog(@"-----%@", [NSThread currentThread]);
            }
        }];
    }
    

    能够开启新线程,进行并发执行

    4.控制串行执行和并行执行的关键

    最大并发数:maxConcurrentOperationCount
    maxConcurrentOperationCount默认情况下为-1,表示不进行限制,默认为并发执行。
    当maxConcurrentOperationCount为1时,进行串行执行。
    当maxConcurrentOperationCount大于1时,进行并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整。

    // 创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 设置最大并发操作数
        //    queue.maxConcurrentOperationCount = 2;
        queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
    

    5.操作依赖

    NSOperation和NSOperationQueue最吸引人的地方是它能添加操作之间的依赖关系。比如说有A、B两个操作,其中A执行完操作,B才能执行操作,那么就需要让B依赖于A。具体如下

    - (void)addDependency
    {
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"1-----%@", [NSThread  currentThread]);
        }];
        NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"2-----%@", [NSThread  currentThread]);
        }];
    
        [op2 addDependency:op1];    // 让op2 依赖于 op1,则先执行op1,在执行op2
    
        [queue addOperation:op1];
        [queue addOperation:op2];
    }
    

    6.一些其他方法

    - (void)cancel;NSOperation提供的方法,可取消单个操作
    - (void)cancelAllOperations;NSOperationQueue提供的方法,可以取消队列的所有操作
    - (void)setSuspended:(BOOL)b;可设置任务的暂停和恢复,YES代表暂停队列,NO代表恢复队列
    - (BOOL)isSuspended;判断暂停状态
    注意:
    这里的暂停和取消并不代表可以将当前的操作立即取消,而是当当前的操作执行完毕之后不再执行新的操作。
    暂停和取消的区别就在于:暂停操作之后还可以恢复操作,继续向下执行;而取消操作之后,所有的操作就清空了,无法再接着执行剩下的操作。

    以上部分资料感谢https://www.jianshu.com/p/4b1d77054b35

    相关文章

      网友评论

          本文标题:多线程

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