iOS多线程

整理下几种常用的处理多线程的类,并将该类对应的常用方法整理下,采用简单直观的例子展示。

1、NSThread

NSThread的创建方法有三种:

  • init方法,需要start启动
  • detachNewThreadSelector方法,自动启动
  • performSelectorInBackground方法,自动启动

init方法

NSThread *threadInit = [[NSThread alloc] initWithTarget:self selector:@selector(thread_initMethod:) object:@"initMethod"];
[threadInit start];
- (void)thread_initMethod:(NSObject *)object
{
    NSLog(@"init方法 --> object:%@, %@",object, [NSThread currentThread]);
}

输出结果:

init方法 --> object:initMethod, {number = 3, name = (null)}

是在子线程中完成。

detachNewThreadSelector方法

[NSThread detachNewThreadSelector:@selector(thread_detch:) toTarget:self withObject:@"detachNewThread"];
- (void)thread_detch:(NSObject *)object
{
    NSLog(@"detach方法 --> object:%@, %@",object, [NSThread currentThread]);
}

输出结果:

detach方法 --> object:detachNewThread, {number = 4, name = (null)}

是在子线程中完成。

performSelectorInBackground方法

[self performSelectorInBackground:@selector(thread_perform:) withObject:@"performSelectorInBackground"];
- (void)thread_perform:(NSObject *)object
{
    NSLog(@"perform方法--> object:%@, %@",object, [NSThread currentThread]);
}

输出结果:

perform方法--> object:performSelectorInBackground, {number = 5, name = (null)}

是在子线程中完成。

2、GCD

GCD中的基本概念:

  • 任务:执行的代码块
  • 队列:存放任务的地方
  • 同步/异步:执行的方式

GCD中的三种队列类型:

  • The main queue:与主线程功能相同。实际上,提交至main queue(主队列)的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
  • Global queues:全局队列是并发队列,并由整个进程共享。进程中存在四个全局队列:高、中(默认)、低、后台四个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
  • 其他队列: 其他队列是用函数dispatch_queue_create创建的队列。创建队列,第一个参数是表示debug用的,Apple建议我们使用倒置域名来命名队列;第二个参数表示队列类型:串行(DISPATCH_QUEUE_SERIAL)或者并发(DISPATCH_QUEUE_CONCURRENT)。

串行同步

dispatch_queue_t serialQueue = dispatch_queue_create("com.multithreading.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行同步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_sync(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行同步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_sync(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行同步:%i --> %@",i, [NSThread currentThread]);
    }
});

输出结果:

串行同步:0 --> {number = 1, name = main}
串行同步:1 --> {number = 1, name = main}
串行同步:2 --> {number = 1, name = main}
串行同步:0 --> {number = 1, name = main}
串行同步:1 --> {number = 1, name = main}
串行同步:2 --> {number = 1, name = main}
串行同步:0 --> {number = 1, name = main}
串行同步:1 --> {number = 1, name = main}
串行同步:2 --> {number = 1, name = main}

都是在主线程中完成,没有开辟新线程。

串行异步

dispatch_queue_t serialQueue = dispatch_queue_create("com.multithreading.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行异步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行异步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(serialQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行异步:%i --> %@",i, [NSThread currentThread]);
    }
});

输出结果:

串行异步:0 --> {number = 3, name = (null)}
串行异步:1 --> {number = 3, name = (null)}
串行异步:2 --> {number = 3, name = (null)}
串行异步:0 --> {number = 3, name = (null)}
串行异步:1 --> {number = 3, name = (null)}
串行异步:2 --> {number = 3, name = (null)}
串行异步:0 --> {number = 3, name = (null)}
串行异步:1 --> {number = 3, name = (null)}
串行异步:2 --> {number = 3, name = (null)}

开辟了一个新线程。

并发同步

dispatch_queue_t concurrentQueue = dispatch_queue_create("com.multithreading.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发同步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_sync(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发同步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_sync(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发同步:%i --> %@",i, [NSThread currentThread]);
    }
});

输出结果:

并发同步:0 --> {number = 1, name = main}
并发同步:1 --> {number = 1, name = main}
并发同步:2 --> {number = 1, name = main}
并发同步:0 --> {number = 1, name = main}
并发同步:1 --> {number = 1, name = main}
并发同步:2 --> {number = 1, name = main}
并发同步:0 --> {number = 1, name = main}
并发同步:1 --> {number = 1, name = main}
并发同步:2 --> {number = 1, name = main}

在主线程中完成,没有开辟新线程。

并发异步

dispatch_queue_t concurrentQueue = dispatch_queue_create("com.multithreading.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发异步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发异步:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(concurrentQueue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"并发异步:%i --> %@",i, [NSThread currentThread]);
    }
});

输出结果:

并发异步:0 --> {number = 4, name = (null)}
并发异步:0 --> {number = 3, name = (null)}
并发异步:0 --> {number = 5, name = (null)}
并发异步:1 --> {number = 4, name = (null)}
并发异步:1 --> {number = 3, name = (null)}
并发异步:1 --> {number = 5, name = (null)}
并发异步:2 --> {number = 4, name = (null)}
并发异步:2 --> {number = 3, name = (null)}
并发异步:2 --> {number = 5, name = (null)}

本例子中开了三条新线程。

主线程同步

- (void)mainQueueSync
{
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"任务1:%@",[NSThread currentThread]);
    });
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"任务2:%@",[NSThread currentThread]);
    });
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"任务3:%@",[NSThread currentThread]);
    });
}

输出结果:

主线程锁死,崩溃

原因:主队列同步会先执行任务1,当前主线程正在执行mainQueueSync方法,造成执行任务1等待mainQueueSync方法结束,mainQueueSync方法等待任务1~3任务结束。

线程通讯

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"做一些费时的东西");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"主线程刷新UI");
    });
});

输出结果:

做一些费时的东西
主线程刷新UI

栅栏

dispatch_queue_t queue = dispatch_queue_create("com.multithreading.fence", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务1:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务2:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_barrier_async(queue, ^{
    NSLog(@"------并发异步执行栅栏分割------");
});
dispatch_async(queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务3:%i --> %@",i, [NSThread currentThread]);
    }
});
dispatch_async(queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务4:%i --> %@",i, [NSThread currentThread]);
    }
});

输出结果:

任务2:0 --> {number = 4, name = (null)}
任务1:0 --> {number = 3, name = (null)}
任务2:1 --> {number = 4, name = (null)}
任务1:1 --> {number = 3, name = (null)}
任务2:2 --> {number = 4, name = (null)}
任务1:2 --> {number = 3, name = (null)}
------并发异步执行栅栏分割------
任务4:0 --> {number = 4, name = (null)}
任务3:0 --> {number = 3, name = (null)}
任务4:1 --> {number = 4, name = (null)}
任务3:1 --> {number = 3, name = (null)}
任务4:2 --> {number = 4, name = (null)}
任务3:2 --> {number = 3, name = (null)}

异步是没有顺序的,但是添加了栅栏,可以将任务分为两部分,先做第一部分完毕后,才会做第二部分。

队列组

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("com.multithreading.group", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务1:%i --> %@",i,[NSThread currentThread]);
    }
});
dispatch_group_async(group, queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务2:%i --> %@",i,[NSThread currentThread]);
    }
});
dispatch_group_async(group, queue, ^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务3:%i --> %@",i,[NSThread currentThread]);
    }
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"任务完了,回到主线程刷新UI");
});

输出结果:

任务1:0 --> {number = 3, name = (null)}
任务3:0 --> {number = 5, name = (null)}
任务2:0 --> {number = 4, name = (null)}
任务1:1 --> {number = 3, name = (null)}
任务2:1 --> {number = 4, name = (null)}
任务3:1 --> {number = 5, name = (null)}
任务1:2 --> {number = 3, name = (null)}
任务2:2 --> {number = 4, name = (null)}
任务3:2 --> {number = 5, name = (null)}
任务完了,回到主线程刷新UI

开辟了三条线程,在任务1,2,3完成后会,回调dispatch_group_notify方法,回到主线程刷新UI。

3、NSOperation

NSOperation的创建:

  • 使用NSInvocationOperation子类,需要start开启
  • 使用NSBlockOperation子类,需要start开启
  • 使用继承NSOperation的子类,需要start开启

NSInvocationOperation

NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation:) object:@"invocation"];
[invocationOperation start];
- (void)invocationOperation:(NSObject *)object
{
    NSLog(@"invocation方法:%@",[NSThread currentThread]);
}

输出结果:

invocation方法:{number = 1, name = main}

没有开新线程。

NSBlockOperation

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"block方法:%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"任务1:%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"任务2:%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"任务3:%@",[NSThread currentThread]);
}];
[blockOperation start];

输出结果:

block方法:{number = 1, name = main}
任务1:{number = 2, name = (null)}
任务2:{number = 3, name = (null)}
任务3:{number = 4, name = (null)}

blockOperationWithBlock方法:主线程实现,不加入队列就不会开辟新线程
addExecutionBlock方法:会开新线程

继承NSOperation的子类

此例子中继承NSOperation的子类名为DZROperation ,在.m文件中重写main函数来实现任务

// DZROperation.h
#import 

@interface DZROperation : NSOperation

@end


// DZROperation.m
#import "DZROperation.h"

@implementation DZROperation

- (void)main
{
    for (int i = 0; i < 3; i++) {
        NSLog(@"DZROperation --> %i, %@",i, [NSThread currentThread]);
    }
}

@end
DZROperation *operation = [[DZROperation alloc] init];
[operation start];

输出结果:

DZROperation --> 0, {number = 1, name = main}
DZROperation --> 1, {number = 1, name = main}
DZROperation --> 2, {number = 1, name = main}

没有加入队列,是在主线程中实现,未开辟新线程。

NSOperationQueue

NSOperationQueue队列类型:

  • 主队列
  • 非主队列(串行,并发)

队列NSOperationQueue有个参数最大并发数:maxConcurrentOperationCount

  • maxConcurrentOperationCount默认-1,直接开启并发,所以非主队列默认是开启并发
  • maxConcurrentOperationCount > 1,进行并发
  • maxConcurrentOperationCount = 1,表示不开线程,是串行
  • maxConcurrentOperationCount系统会限制一个最大值,所以设maxConcurrentOperationCount很大也是无意义的
添加自定义NSOperation类到队列中
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
DZROperation *operation1 = [[DZROperation alloc] init];
DZROperation *operation2 = [[DZROperation alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];

输出结果:

DZROperation --> 0, {number = 2, name = (null)}
DZROperation --> 0, {number = 3, name = (null)}
DZROperation --> 1, {number = 2, name = (null)}
DZROperation --> 1, {number = 3, name = (null)}
DZROperation --> 2, {number = 2, name = (null)}
DZROperation --> 2, {number = 3, name = (null)}

此处的NSOperationQueue是默认并发队列,这里开了2个新线程

直接添加任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{
    NSLog(@"添加任务1:%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
    NSLog(@"添加任务2:%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
    NSLog(@"添加任务3:%@",[NSThread currentThread]);
}];

输出结果:

maxConcurrentOperationCount = -1输出:
添加任务2:{number = 3, name = (null)}
添加任务1:{number = 2, name = (null)}
添加任务3:{number = 4, name = (null)}

maxConcurrentOperationCount = 1输出:
添加任务1:{number = 2, name = (null)}
添加任务2:{number = 2, name = (null)}
添加任务3:{number = 2, name = (null)}

直接在block中实现任务。

operationQueue间通讯
// 主队列
NSOperationQueue *mainOperation = [NSOperationQueue mainQueue];
// 并发队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
    NSLog(@"做复杂操作");
    
    [mainOperation addOperationWithBlock:^{
        NSLog(@"刷新UI");
    }];
}];

输出结果:

做复杂操作
刷新UI

任务的执行先后设定 -- 类似GCD的栅栏
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务1:%d, %@",i, [NSThread currentThread]);
    }
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"任务2:%d, %@",i, [NSThread currentThread]);
    }
}];

// 任务1依赖任务2
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];

输出结果:

任务2:0, {number = 2, name = (null)}
任务2:1, {number = 2, name = (null)}
任务2:2, {number = 2, name = (null)}
任务1:0, {number = 2, name = (null)}
任务1:1, {number = 2, name = (null)}
任务1:2, {number = 2, name = (null)}

依赖关系,任务1依赖任务2,任务2完成后才能完成任务1。但是不能相互依赖,会造成锁死。

最最后:
详情demo请转接这里。

你可能感兴趣的:(iOS多线程)