什么是多线程?
要知道什么是多线程首先要了解进程和线程的概念。
进程:
指系统中正在运行的应用程序,而且每个进程之间是相互独立的
线程:
程序执行的基本单元,程序中的任务都在线程中执行
线程中执行任务的方式分为串行和并行,串行指所有任务按照顺序依次执行,并行是指在一个线程中多个任务同时执行
多线程:
在一个进程中可以开辟多个线程来同时(并行)运行,每个线程也可串行或并行执行任务。但是CPU同一时间只能处理一条线程,多线程并发执行其实是由于CPU运行速度足够快,在多条线程之间进行调度,造成了多条线程并发执行的假象,如果有非常多的线程同时执行,也许会造成CPU崩溃
多线程的优缺点:
多线程的优缺点
优点:
①能适当提高程序的执行效率
②能适当提高资源利用率(CPU、内存利用率)
缺点:
①开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
②线程越多,CPU在调度线程上的开销就越大
③程序设计更加复杂:比如线程之间的通信、多线程的数据共享
iOS里面实现多线程的方案:
#######iOS中目前多线程有4套实现方案:
Pthread:
这是一套在很多操作系统上都通用的多线程API,移植性很强。不过这是基于c语言的框架,使用起来有点困难,对程序猿的技术要求略高
NSThread:
是相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步。线程共享同一应用程序的部分内存空间,它们拥有对数据相同的访问权限。
GCD:
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法。GCD是一个替代诸如NSThread等技术的很高效和强大的技术。GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题。GCD的工作原理是让一个程序,根据可用的处理资源,安排他们在任何可用的处理器核心上平行排队执行特定的任务。这个任务可以是一个功能或者一个程序段。这是iOS开发中最多使用的多线程实现方案
NSOperation:
NSOperation实际上是苹果对GCD的封装,相对于GCD来说可控性更高,NSOperation实际上是一个抽象的基类,并不能直接使用,需要通过继承于它的子类来调用各种方法实现功能
简单实现
pthread:
首先当然是导入头文件
<pre><code>
import "pThread"
</code></pre>
假设我们有一耗时操作(写成函数指针形式)
void *run(void *costTime) {
for (NSInteger i = 0; i < 10000; i++) {
NSLog(@"%ld", i)
}
}
这里我是设置一个Button的点击事件来执行
- (void)btnClick {
pthread_t pThread;
pthread_create(&pthread, NULL, run, NULL);
// 第一个参数:线程指针
// 第二个参数:线程的一些属性
// 第三个参数:用于执行方法的函数指针
// 第四个参数:线程中的传值
}
这样就创建了一条线程来执行函数costTime,主线程的任务可以继续执行,不必等待
NSThread:
- (void)creadNSThread
{
// 创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(costTime) object:@"111"];
thread.name = @"222";
// 开启线程
[thread start];
NSLog(@"%@", [NSThread currentThread]);//当前线程
NSLog(@"%@", [NSThread mainThread]);//主线程
NSLog(@"%d", [NSThread isMainThread]);//是否为主线程
}
// 快捷创建方式
- (void)creatNSThread1
{
// 快捷创建 无返回值
[NSThread detachNewThreadSelector:@selector(costTime) toTarget:self withObject:nil];
}
NSOperation:
- (void)createNSOperation
{
NSInvocationOperation *operation_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction1) object:nil];
NSInvocationOperation *operation_2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction2) object:nil];
// block方式创建多线程
NSBlockOperation *operation_3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"第三个 -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第三个 -- %d", i);
}
}];
// 操作队列
// 目的:将任务放在一个队列中执行
// 任务:任务执行在主线程还是在子线程全部都是由我们的队列来决定的
// 获取主队列
// NSOperationQueue *queue = [NSOperationQueue mainQueue];
// alloc init 的代表字其他队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 先加入队列的先执行,但是执行的时间不定,可能后执行的比先执行的先执行完
[queue addOperation:operation_1];
[queue addOperation:operation_2];
[queue addOperation:operation_3];
}
- (void)operationAction1
{
NSLog(@"第一个 -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第一个 -- %d", i);
}
}
- (void)operationAction2
{
NSLog(@"第二个 -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第二个 -- %d", i);
}
}
GCD:
- (void)viewDidLoad {
[super viewDidLoad];
// 下面这种方式中,最内层的任务永远不会执行,因为任务2要等待任务执行完才会执行,而任务2又在任务1中,造成类似死循环
// 所以这里是一个错误演示
dispatch_queue_t queue = dispatch_queue_create("sss", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1 --- %@", [NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"2 --- %@", [NSThread currentThread]);
});
});
}
实现:
根据GCD执行方式,可将其分为几种类型
根据线程执行方式分为同步:同一个线程顺序执行 异步:不在一个线程执行
根据任务执行方式串行:串在一起执行 并行:一起执行
主队列不会开辟新的线程,所以使用主线程执行任务只有同步串行一种方式
// 此处只实现异步并发方式
// 异步 + 并发队列 具备开启子线程的能力,并且并发执行任务
- (void)createAsyncConcurrent
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1 --- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3 --- %@", [NSThread currentThread]);
});
}