整理下几种常用的处理多线程的类,并将该类对应的常用方法整理下,采用简单直观的例子展示。
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, <NSThread: 0x60000027b180>{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, <NSThread: 0x60000027b0c0>{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, <NSThread: 0x60000007a2c0>{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 --> <NSThread: 0x600000072d40>{number = 1, name = main}
串行同步:1 --> <NSThread: 0x600000072d40>{number = 1, name = main}
串行同步:2 --> <NSThread: 0x600000072d40>{number = 1, name = main}
串行同步:0 --> <NSThread: 0x60400007ee80>{number = 1, name = main}
串行同步:1 --> <NSThread: 0x60400007ee80>{number = 1, name = main}
串行同步:2 --> <NSThread: 0x60400007ee80>{number = 1, name = main}
串行同步:0 --> <NSThread: 0x60400007ee80>{number = 1, name = main}
串行同步:1 --> <NSThread: 0x60400007ee80>{number = 1, name = main}
串行同步:2 --> <NSThread: 0x60400007ee80>{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 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:1 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:2 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:0 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:1 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:2 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:0 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:1 --> <NSThread: 0x604000467900>{number = 3, name = (null)}
串行异步:2 --> <NSThread: 0x604000467900>{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 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:1 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:2 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:0 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:1 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:2 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:0 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:1 --> <NSThread: 0x60000007c980>{number = 1, name = main}
并发同步:2 --> <NSThread: 0x60000007c980>{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 --> <NSThread: 0x600000277480>{number = 4, name = (null)}
并发异步:0 --> <NSThread: 0x604000465f80>{number = 3, name = (null)}
并发异步:0 --> <NSThread: 0x604000466140>{number = 5, name = (null)}
并发异步:1 --> <NSThread: 0x600000277480>{number = 4, name = (null)}
并发异步:1 --> <NSThread: 0x604000465f80>{number = 3, name = (null)}
并发异步:1 --> <NSThread: 0x604000466140>{number = 5, name = (null)}
并发异步:2 --> <NSThread: 0x600000277480>{number = 4, name = (null)}
并发异步:2 --> <NSThread: 0x604000465f80>{number = 3, name = (null)}
并发异步:2 --> <NSThread: 0x604000466140>{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 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务1:0 --> <NSThread: 0x60000026b780>{number = 3, name = (null)}
任务2:1 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务1:1 --> <NSThread: 0x60000026b780>{number = 3, name = (null)}
任务2:2 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务1:2 --> <NSThread: 0x60000026b780>{number = 3, name = (null)}
------并发异步执行栅栏分割------
任务4:0 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务3:0 --> <NSThread: 0x60000026b780>{number = 3, name = (null)}
任务4:1 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务3:1 --> <NSThread: 0x60000026b780>{number = 3, name = (null)}
任务4:2 --> <NSThread: 0x604000069940>{number = 4, name = (null)}
任务3:2 --> <NSThread: 0x60000026b780>{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 --> <NSThread: 0x60400027a080>{number = 3, name = (null)}
任务3:0 --> <NSThread: 0x604000279fc0>{number = 5, name = (null)}
任务2:0 --> <NSThread: 0x60400027a0c0>{number = 4, name = (null)}
任务1:1 --> <NSThread: 0x60400027a080>{number = 3, name = (null)}
任务2:1 --> <NSThread: 0x60400027a0c0>{number = 4, name = (null)}
任务3:1 --> <NSThread: 0x604000279fc0>{number = 5, name = (null)}
任务1:2 --> <NSThread: 0x60400027a080>{number = 3, name = (null)}
任务2:2 --> <NSThread: 0x60400027a0c0>{number = 4, name = (null)}
任务3:2 --> <NSThread: 0x604000279fc0>{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方法:<NSThread: 0x600000071ec0>{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方法:<NSThread: 0x7feaf1701590>{number = 1, name = main}
任务1:<NSThread: 0x7f839bc21280>{number = 2, name = (null)}
任务2:<NSThread: 0x7f839be44180>{number = 3, name = (null)}
任务3:<NSThread: 0x7f839be1f470>{number = 4, name = (null)}
blockOperationWithBlock
方法:主线程实现,不加入队列就不会开辟新线程
addExecutionBlock
方法:会开新线程
继承NSOperation的子类
此例子中继承NSOperation的子类名为DZROperation
,在.m文件中重写main
函数来实现任务
// DZROperation.h
#import <Foundation/Foundation.h>
@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, <NSThread: 0x7fd22ee01ae0>{number = 1, name = main}
DZROperation --> 1, <NSThread: 0x7fd22ee01ae0>{number = 1, name = main}
DZROperation --> 2, <NSThread: 0x7fd22ee01ae0>{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, <NSThread: 0x7fc46660c030>{number = 2, name = (null)}
DZROperation --> 0, <NSThread: 0x7fc466605c70>{number = 3, name = (null)}
DZROperation --> 1, <NSThread: 0x7fc46660c030>{number = 2, name = (null)}
DZROperation --> 1, <NSThread: 0x7fc466605c70>{number = 3, name = (null)}
DZROperation --> 2, <NSThread: 0x7fc46660c030>{number = 2, name = (null)}
DZROperation --> 2, <NSThread: 0x7fc466605c70>{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:<NSThread: 0x7fa3a2f169f0>{number = 3, name = (null)}
添加任务1:<NSThread: 0x7fa3a2d09240>{number = 2, name = (null)}
添加任务3:<NSThread: 0x7fa3a2d0a3d0>{number = 4, name = (null)}maxConcurrentOperationCount = 1输出:
添加任务1:<NSThread: 0x7fe65270b6a0>{number = 2, name = (null)}
添加任务2:<NSThread: 0x7fe65270b6a0>{number = 2, name = (null)}
添加任务3:<NSThread: 0x7fe65270b6a0>{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, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
任务2:1, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
任务2:2, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
任务1:0, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
任务1:1, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
任务1:2, <NSThread: 0x7fc82160c390>{number = 2, name = (null)}
依赖关系,任务1依赖任务2,任务2完成后才能完成任务1。但是不能相互依赖,会造成锁死。
最最后:
详情demo请转接这里。
网友评论