iOS多线程-全面总结
- 进程和线程
进程:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础(百度百科)
根据百度百科的解释我们知道进程是系统进行资源分配和调度的基本单位,在手机端一个进程就是一个app
线程:
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。(百度百科)
根据百度百科我们知道,线程来说其实是进程一个实体
一个进程中至少有一条线程,这条线程我们称为主线程
- iOS中的创建线程和操作线程
- pThread:纯c语言编写,需要自己管理线程的声明周期
OS X and iOS provide C-based support for creating threads using the POSIX thread API. This technology can actually be used in any type of application (including Cocoa and Cocoa Touch applications) and might be more convenient if you are writing your software for multiple platforms. The POSIX routine you use to create threads is called, appropriately enough, pthread_create.(苹果官方文档)
官方文档上说,这是一个基于C语言的创建和使用线程的API,而且是一个跨平台的API。查看官方文档https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW12
- NSThread:OC封装面向对象,需要自己管理线程释放,相对用起来比较简单
四种创建方式:
// 1.需要调用start,才会去创建线程加入到当前队列
NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
// 2.iOS10新加入的方法,同上
NSThread *thread = [[NSThread alloc] initWithBlock:^{
}];
[myThread start]; // Actually create the thread
// 3.detach 直接创建线程,加入当前队列
[NSThread detachNewThreadWithBlock:^{
[self task];
}]; //@available iOS10
// 4.同上
[NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
还有一些实用的熟悉和方法比如
currentThread、isMultiThreaded、
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
+ (void)exit; 等等如果查看NSThread.h文件
pThread、NSThread 都需要我们自己去创建管理线程的声明周期,所以之后出现了不要我们管理线程的生命周期的 GCD、NSOpration。
- GCD:API基于C语言, 我们需要关心的概念是队列、任务,不在需要管理线程问题,CGD自动创建、分配、管理线程。
下面我们通过具体的代码例子,引出结论和理解:
- 同步队列
NSLog(@"当前线程:%@", [NSThread currentThread]);
dispatch_queue_t testQueue = dispatch_queue_create("com.haoyuhong.testQueue", NULL);
/// 同步执行, 当前主线程串行执行
dispatch_sync(testQueue, ^{
NSLog(@"2. 当前线程: %@", [NSThread currentThread]);
});
/// 异步执行, 分配新线程执行
dispatch_async(testQueue, ^{
NSLog(@"3. 当前线程: %@", [NSThread currentThread]);
});
/// 异步执行,在已经分配的线程串行执行
dispatch_async(testQueue, ^{
NSLog(@"4. 当前线程: %@", [NSThread currentThread]);
});
输出结果
当前线程:<NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125511+0800 TestGCD[95991:16450263] 2. 当前线程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125671+0800 TestGCD[95991:16450326] 3. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.125765+0800 TestGCD[95991:16450326] 4. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
我们得出以下结论:
* 串行队列总结: 串行队列,特点:保证顺序执行。
1. 如若同步执行,不分配线程,在当前线程串行执行;
2. 如若,异步执行,不阻塞当前线程,如果没有开辟新线程则开辟新线程,如果已经开辟了一条线程,则任务会在开辟的线程中串行执行,保持顺序执行。
死锁: 造成死锁的原因就是:相互等待,串行队列的特点就是顺序执行,如果同步执行任务在当前串行队列中执行,就会造成死锁。
- 并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.haoyuhong.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
/// 并发队列,同步任务,不分配线程,在当前线程执行
dispatch_sync(concurrentQueue, ^{
NSLog(@"1. 当前线程: %@", [NSThread currentThread]);
});
/// 并发队列,异步任务,分配线程,并发执行
dispatch_async(concurrentQueue, ^{
NSLog(@"2. 当前线程: %@", [NSThread currentThread]);
});
/// 并发队列,异步任务,分配线程,并发执行
dispatch_async(concurrentQueue, ^{
NSLog(@"3. 当前线程: %@", [NSThread currentThread]);
});
## 输出结果
2019-09-03 15:50:48.126185+0800 TestGCD[95991:16450263] 1. 当前线程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.126313+0800 TestGCD[95991:16450326] 2. 当前线程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.126345+0800 TestGCD[95991:16450325] 3. 当前线程: <NSThread: 0x6000028d1b80>{number = 5, name = (null)}
总结如下
并发队列, 特点:并发执行
1. 同步任务,队列不会分配新线程去执行,在当前线程串行执行
2. 异步任务,队列分配新线程,所有异步任务,并发执行
-
系统队列:
- 主队列
串行队列,不管是同步还是异步,都不会创建新线程,所有任务都是在主线程执行,所以他是一种特殊的串行队列。如果当前执行线程为主线程,添加同步任务会造成,互相等待状态,导致死锁;异步执行,等待主线程此异步任务之前所有任务执行完毕执行。
获取函数:dispatch_get_main_queue() - 全局队列
并发队列。
获取函数:dispatch_get_global_queue(0, 0)
第一个参数,服务质量决定任务执行的优先级
The quality of service you want to give to tasks executed using this queue. Quality-of-service helps determine the priority given to tasks executed by the queue.QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_USER_INITIATED, QOS_CLASS_UTILITY, or QOS_CLASS_BACKGROUND
- 主队列
-
DispatchGroup
dispatch_group: 将队列添加到队列组里
队列组可以添加一个任务到队列并且将队列加入队列组dispatch_group_create() /// 创建分发组
dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 添加block任务到队列,并且关联到分发组void
dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 监听所有队列里的任务都完成后执行block里的任务dispatch_group_wait(group, DISPATCH_TIME_FOREVER); /// 同步等待所有之前加入的任务都执行完毕
-
栅栏函数
栅栏函数:保证之前加入的任务都执行完毕,之后加入的任务等待栅栏任务执行完毕。- dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
- void
dispatch_barrier_sync(dispatch_queue_t queue,
DISPATCH_NOESCAPE dispatch_block_t block);
void
-
延迟执行:
- dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
- dispatch_after(dispatch_time_t when,
-
执行一次函数:应用于单利的创建
- dispatch_once(dispatch_once_t *predicate,
DISPATCH_NOESCAPE dispatch_block_t block);
- dispatch_once(dispatch_once_t *predicate,
-
NSOperation
NSOperation 是一个抽象任务类,不能直接使用,需要实例化两个子类使用,基于GCD的封装,将多线程简单化为队列和任务,使用起来也是很简单的
*它与CGD的区别就是GCD是更底层的封装,在性能上会比NSOperation好点NSBlockOperation:用一个block的方式初始化一个任务
实例化:
NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”1-%@”, [NSThread currentThread]);
}];NSInvocationOperation:Target-Action的方式初始一个任务
初始化方式:
NSInvocationOperation *task2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];-
NSOperationQueue :任务运行队列
init方式初始:初始化一个并行队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
mianQueue方式获取主队列:获取主队列,是一个串行队列
NSOperationQueue *queue = [NSOperationQueue mainQueue];- 直接添加任务block到队列
– (void)addOperationWithBlock:(void (^)(void))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); - 设置并发数:maxConcurrentOperationCount
- 挂起当前队列:suspended
- 设置队列的优先级:qualityOfService
- 取消队列所有任务: cancelAllOperations
- 等待所有队列任务执行完成:
– (void)waitUntilAllOperationsAreFinished;
- 直接添加任务block到队列
添加任务依赖:一个任务需要依赖另外一个任务执行完成才能执行
– (void)addDependency:(NSOperation *)op;
*移除依赖关系:
– (void)removeDependency:(NSOperation *)op;
以上iOS多线程中知识,在此做一个总结,一起共勉!