多线程

2016-12-22  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读