多线程编程
来源:互联网 发布:怎样写淘宝直通车标题 编辑:程序博客网 时间:2024/06/08 14:25
</pre><p>首先要强调的是数组的并行和串行两种执行方式。</p><p></p><pre name="code" class="objc"> NSArray *array = @[@1,@2,@3,@4,@5]; //数组排序: //NSSortStable:串行,在排序执行的时候,程序为顺序结构执行,排序不执行完成,后期的代码不会运行。(耗时间,但结果安全) //NSSortConcurrent:并行,在程序执行的时候,程序为多线程方式,排序方法执行的时候,下面的代码也同步执行。(节省时间,结果不安全) [array sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2]; }]; NSLog(@"%@",array);
现在开始步入正题,这节课我们讲的是iOS高级编程中的多线程编程。
程序是什么?
程序是由源代码生成的可执行应用。
进程是什么?
进程:一个正在运行的程序可以看错一个进程。进程拥有独立运行所需的全部资源。
线程是什么?
线程是程序中独立运行的代码段。
程序,进程,线程之间的关系呢?
一个进程是由一个或多个线程组成,进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。
单线程?
每个正在运行的程序(即进程)至少包含一个线程,这个线程叫主线程。
主线程在程序启动时被创建,用于执行main函数。
只有一个主线程的程序,称作单线程程序。
主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。
多线程?
拥有多个线程的程序,称为多线程程序。
iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。
可以根据需要开辟若干子线程。
子线程和主线程都是独立的运行单元,各自的执行互不影响,因此能够并发执行。
单线程和多线程的区别?
单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)
多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。
注意:iOS中关于UI的添加和刷新必须在主线程中操作。
iOS平台下得多线程
多线程的种类
1.脱离线程
2.非脱离线程
iOS多线程实现种类
NSObect 实现异步后台执行
NSObject中存在了一个最简单的后台执行的方法
//NSObject 多线程方式 后台执行某个方法 [self performSelectorInBackground:@selector(calculate) withObject:nil];
NSThread
是一个轻量级的多线程,它有以下两种创建方法。
//NSThread 多线程方式 //方式1 初始化一个子线程,但需要手动开启 NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(calculate) object:nil]; [thread1 start]; //开启子线程,concel取消子线程 //方式2 初始化一个子线程并自动开启 [NSThread detachNewThreadSelector:@selector(calculate) toTarget:self withObject:nil];
注意:在多线程方法中需要添加自动释放池
在应用程序打开的时候,系统会自动为主线程创建一个自动释放池
我们手动创建的子线程需要我们手动添加自动释放池!
NSOperationQueue
NSOperation类,在MVC中属于M,是用来封装单个任务相关的代码和数据的抽象类。
因为它是抽象的,不能够直接使用这个类,而是使用子类(NSInvocationOperation或NSBlockOperation)来执行实际任务
NSOperation(含子类),只是一个操作,本身无主线程、子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。
NSInvocationOperation是NSOperation的子类
封装了执行操作的target和要执行的action
NSBlockOperation是NSOperation的子类
封装了需要执行的代码块
NSOperationQueue是操作队列,他用来管理一组Operation对象的执行,会根据需要自动为Operation开辟合适数量的线程,以完成任务的并行执行。
其中NSOperation可以调节它在队列中的优先级。
当最大并发数设置为1的时候,能实现线程同步。
//NSOperation/NSOperationQueue 多线程方式 //方式一NSInvocationOperation NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printNumber) object:nil];#warning 需要手动开启 辅助实现多线程// [invocation start]; //方式二NSBlockOperation Block会持有内部变量 __weak typeof(self) temp = self; NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{ [temp printAnotherGroupNumber]; }];// [block start]; //可以通过NSOperationQueue创建队列,向队列中添加操作,完成多任务同时执行,当最大并发数为1,变成了串行。 NSOperationQueue *queue = [[NSOperationQueue alloc]init];#warning 一定要提前设置好并发数 决定是否能够并发进行 如上所述 [queue setMaxConcurrentOperationCount:1]; [queue addOperation:invocation]; [queue addOperation:block];- (void)printNumber{ for (int i =0; i<10; i++) { NSLog(@"1"); }}- (void)printAnotherGroupNumber{ for (int i =0; i<10; i++) { NSLog(@"2"); }}- (void)calculate{#warning 一定要写自动释放池 @autoreleasepool { NSArray *array = @[@1,@2,@3,@4,@5]; for (int i = 0; i <10; i++) { array = [array arrayByAddingObjectsFromArray:array]; } NSLog(@"%@",array); self.view.backgroundColor = [UIColor redColor]; NSLog(@"%d",[NSThread isMainThread]); }}- (void)test{ @autoreleasepool { NSArray *array = @[@1,@2,@3,@4,@5]; for (int i = 0; i <18; i++) { array = [array arrayByAddingObjectsFromArray:array]; } NSLog(@"%@",array); self.view.backgroundColor = [UIColor blackColor]; NSLog(@"%d",[NSThread isMainThread]); NSLog(@"这是另外一个线程的方法"); }}
GCD (Grand Central Dispatch) 中央调度
1.主队列
2.全局队列
3.自定义队列{串行队列,并行队列}
GCD简介
Grand Central Dispatch 简称(GCD)是苹果公司开发的技术。
以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。
GCD属于函数级的多线程,性能更高,功能也更加强大。
它首次发布在OS X 10.6 iOS 4及以上也可用
GCD核心概念
任务:具有一定功能的代码段。一般是一个Block或者函数。
分发队列:GCD以队列的方式进行工作,FIFO(First In First Out)
GCD会根据分发队列的类型,创建合适数量的线程执行队列中的任务。
1.主队列
//获取主队列 dispatch_queue_t mainQueue = dispatch_get_main_queue(); //向主队列中添加任务 串行队列 dispatch_async(mainQueue, ^{ NSLog(@"第一个任务..."); }); dispatch_async(mainQueue, ^{ NSLog(@"第二个任务..."); }); dispatch_async(mainQueue, ^{ NSLog(@"第三个任务..."); });延时执行
//设置延时执行 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"这是五年后的你"); }); dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)); //NSEC_PER_MSEC 毫秒 //NSEC_PER_USEC 微秒 dispatch_after(time, mainQueue, ^{ NSLog(@"这是十年后的你"); });
不要再主线程中加入延迟,会造成阻塞。
串行与并行没有关系
主队列与全局队列都是单例,主队列串行,全局队列并行,都是直接获取,直接使用,不需要创建,也就是一直存在。
2.全局队列
//获取全局队列 dispatch_queue_t globelQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //向全局队列中添加任务,串行队列 dispatch_async(globelQueue, ^{ NSLog(@"我"); }); dispatch_async(globelQueue, ^{ NSLog(@"爱"); }); dispatch_async(globelQueue, ^{ NSLog(@"你"); });
重复执行
dispatch_apply(3, globelQueue, ^(size_t t) { NSLog(@"重要的事情说三遍"); NSLog(@"%lu",t); });分组任务
//分组任务 dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, globelQueue, ^{ NSLog(@"第一分组第一小队"); }); dispatch_group_async(group, globelQueue, ^{ NSLog(@"第一分组第二小队"); }); dispatch_group_async(group, globelQueue, ^{ NSLog(@"第一分组第三小队"); });
//与添加在队列的位置有关系,当处于队列末尾的时候,最后执行。 dispatch_group_notify(group, globelQueue, ^{ NSLog(@"你们先来。我不着急。"); });
3.自定义队列
自定义串行队列
//自定义串行队列 //第一个参数:队列标识符,可以获取到某一队列的标识符。 //第二个参数:队列的类型(串行或者并行) dispatch_queue_t serialQueue = dispatch_queue_create("sss", DISPATCH_QUEUE_SERIAL); //添加task dispatch_async(serialQueue, ^{ NSLog(@"王"); }); dispatch_async(serialQueue, ^{ NSLog(@"颜"); }); dispatch_async(serialQueue, ^{ NSLog(@"华"); });自定义并行队列
//自定义并行队列 dispatch_queue_t concurrentQueue = dispatch_queue_create("ccc", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ NSLog(@"111"); }); //将任务添加到队列中,Block不执行完,下面代码不会执行。 dispatch_sync(concurrentQueue, ^{ int sum = 0; for (int i= 0 ; i<635500000; i++) { sum += i; } NSLog(@"都等着我"); }); //将此函数添加到队列的任务中,需要等其执行完成后才可以执行其他队列的任务。 //前提:自定义并行队列。 dispatch_barrier_async(concurrentQueue, ^{ int sum = 0; for (int i= 0 ; i<635500000; i++) { sum += i; } NSLog(@"让我先来"); }); dispatch_async(concurrentQueue, ^{ NSLog(@"222"); });
//GCD 可以使用此函数,向队列中添加函数,让函数执行。 //函数类型 void(*)(void *) dispatch_async_f(concurrentQueue, "string", function);
//dispatch_once 添加的任务 在整个程序运行期间只会执行一次(重复添加无效) static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"哈哈哈哈"); }); dispatch_once(&onceToken, ^{ NSLog(@"哈哈哈哈"); }); dispatch_once(&onceToken, ^{ NSLog(@"哈哈哈哈"); });上述方法 可以用在单例中
伪单例方法
+ (instancetype)shareSingleton{ static Singleton *singleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ singleton = [self new]; }); return singleton;}
线程间通信
分为两种:
主线程进入子线程
子线程回到主线程
方法:
dispatch_get_main_queue() GCD
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait NSObject
线程互斥
线程互斥场景
线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。
互斥无法限制访问者对资源的访问顺序,即访问是无序的,因此需要加上互斥锁来进行顺序访问,最具有代表性的就是买票系统!
NSLock类能协助完成互斥操作。
总结
NSThread、NSOperationQueue、NSObject、GCD都能实现多线程。
GCD是苹果提供的性能更高的方式。
线程尽管提升了性能,但是存在一些访问限制,比如线程同步,线程互斥等。
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- 多线程编程
- Vim技巧5
- OpenCV支持的AVI文件格式
- Mac下Git命令汇总
- Java核心技术第4章(6)
- UVA 11995 I Can Guess the Data Structure!
- 多线程编程
- Android,Java编程小常识
- 矩阵快速幂 CodeForces - 582B Once Again...
- CI轻松整合smarty
- STL-set-用法
- os.getcwd() 返回的到底是什么?
- 文本分类入门(番外篇)特征选择与特征权重计算的区别
- Java复习笔记—面向对象
- Delphi应用程序的调试(1-10)