iOS中的多线程编程
来源:互联网 发布:使用软件 编辑:程序博客网 时间:2024/05/01 05:50
iOS中的多线程编程
关于多线程编程
什么是多线程
简单的来说,并发应用程序中一个单独的执行路径,就是一个线程。
相关术语
- 进程:用于指代一个正在运行的可执行程序,它可以包含多个线程。
- 任务:用于指代抽象的概念,表示需要执行工作。
- 线程的同步:同步就是协同步调,按预定的先后次序进行运行。线程的同步即一个线程执行完指定操作后,另个一个线程再执行。
- 线程的互斥:线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。
iOS中的多线程编程
- pthread(POSIX threads):一套C语言接口,定义了创建和管理线程的API,非常灵活,可以直接操作线程。
- NSThread:一套OC接口,需要自己手动管理线程,比GCD和NSOperation更加轻量级。
- GCD:是iOS4出的一套并发编程的接口,纯C语言接口。以队列为基础。
- NSOperation:一套面向对象的OC API,不需要手动管理线程。能实现一些GCD实现不了的功能。
NSThread
基本操作
线程的创建
- 类方法创建线程
[NSThread detachNewThreadSelector:@selector(threadFun:) toTarget:self withObject:@"helloworld"];
- 实例方法创建线程
NSThread * th = [[NSThread alloc] initWithTarget:self selector:@selector(threadFun:) object:@"helloworld"]; [th start];
- 继承NSThread,重写main方法(与NSOperation类似)
//MyThread.h@interface MyThread : NSThread@end//MyThread.m@implementation MyThread- (void)main { NSLog(@"this is MyThread");}//main.m#import <Foundation/Foundation.h>#import "MyThread.h"int main(int argc, const char * argv[]) { @autoreleasepool { MyThread * th = [[MyThread alloc] init]; [th start]; [[NSRunLoop mainRunLoop] run]; } return 0;}@end
- 其他:NSObject中的方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
线程的基本管理
- 获取主线程
+ (NSThread *)mainThread
- 获取当前线程
+ (NSThread *)currentThread;
- 阻塞当前线程
+ (void)sleepUntilDate:(NSDate *)date;
和+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
- 销毁消除当前线程(currentThread)
+ (void)exit;
- 取消线程
- (void)cancel;
:将线程的状体置为cancelled,并不会停止线程的执行 - 线程键的通讯
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
线程同步与互斥
锁
- @synchronized(obj)对代码段进行加锁,同时只能一个线程访问该代码段
@synchronized(self) { i++; NSLog(@"%ld", i);}
- NSLock:与@synchronized类似
NSLock * lock = [[NSLock alloc] init];if ([lock tryLock]) { [lock lock]; i++; NSLog(@"%ld", i); [lock unlock];}
- NSConditionLock条件锁:在所的基础上添加了条件,只有满足对应的条件,才能打开相应的锁
- (void)startTest { _conLock = [[NSConditionLock alloc] init]; [NSThread detachNewThreadSelector:@selector(threadFun:) toTarget:self withObject:@"top thread"]; for (int i = 0; i < 200; i++) { [NSThread detachNewThreadSelector:@selector(threadFun2:) toTarget:self withObject:@(i)]; }}- (void)threadFun:(id)obj { [_conLock lock]; NSLog(@"%@", obj); [NSThread sleepForTimeInterval:1.0f]; //加锁,条件为10 [_conLock unlockWithCondition:10];}- (void)threadFun2:(id)obj { NSInteger value = [obj integerValue]; //只有到value等于10时,才能成功加锁,否则阻塞 [_conLock lockWhenCondition:value]; NSLog(@"thread%@", obj); [NSThread sleepForTimeInterval:1.0f]; //解锁,并把条件设为value + 3,则下次上锁的条件为13,一次类推13,16,19... [_conLock unlockWithCondition:value + 3];}
输出结果:
- NSRecursiveLock递归锁:同一个线程中,递归或多次调用加锁代码段,不会造成死锁
j = 0;[NSThread detachNewThreadSelector:@selector(threadFun:) toTarget:self withObject:@"top thread1"];[NSThread detachNewThreadSelector:@selector(threadFun:) toTarget:self withObject:@"top thread2"];- (void)threadFun:(id)obj { [self testWith:obj];}- (void)testWith:(id)obj { [_recLock lock]; NSLog(@"test recursive,thread:%@, lock:%ld", obj, j++); [NSThread sleepForTimeInterval:1.0f]; if (j < 10) { [self testWith:obj]; } [_recLock unlock];}
输出结果:
- NSDistributedLock分布式锁:用于多个进程之间互斥访问资源,一般用于Mac开发
条件
使用NSCondition,可以实现多线程的同步,解决类似生产者消费者问题。
#import "testThread.h"@implementation testThread{ NSInteger i; NSCondition * _con; NSMutableArray * _products;}- (void)startTest { _con = [[NSCondition alloc] init]; _products = [[NSMutableArray alloc] init]; [NSThread detachNewThreadSelector:@selector(threadFun2:) toTarget:self withObject:@"thread2"]; [NSThread detachNewThreadSelector:@selector(threadFun2:) toTarget:self withObject:@"thread3"]; [NSThread detachNewThreadSelector:@selector(threadFun1:) toTarget:self withObject:@"thread1"];}- (void)threadFun1:(id)obj { while (1) { [NSThread sleepForTimeInterval:2.0f]; [_products addObject:@"apple"];//生产者创造一个产品 NSLog(@"%@ add one product, product count:%ld", obj, _products.count); [_con signal];//通知消费者,消费产品// [_con broadcast]; }}- (void)threadFun2:(id)obj { while (1) { [_con lock]; [_con wait];//等待生产者的通知 [_products removeObjectAtIndex:0];//消费者消费一个产品 NSLog(@"%@ remove one product, proudct count:%ld", obj, _products.count); [_con unlock]; }}@end
GCD
基本用法
队列
- 串行队列:同时只能执行一个任务
- 所有任务都在同一个线程中执行,FIFO
- 多个串行队列之间是并行执行的,会占用多个线程
- 创建串行队列:
dispatch_queue_t serialQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_get_main_queue();
获取主线程上的一个全局可用的串行队列
- 并行队列:同时可以执行多个任务
- 多个任务在不同的线程上执行,最大并发数(最多起的线程数)由操作系统根据当前的系统状态决定,不可手动设置(NSOperation可以)
- 创建并行队列:
dispatch_queue_t concurrentQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
获取一个全局可用的并行队列
任务
- 同步任务:添加一个任务后,需要等待任务执行完后才能返回
- 无论是串行队列还是并行队列,同步任务都是在主线程上执行的
- 同步任务会阻塞当前线程
- 向主队列中添加同步任务会造成死锁,见死锁①
- 向串行队列中添加嵌套的同步任务会造成死锁,见死锁②
//同步任务dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [NSThread sleepForTimeInterval:1.0f]; //先打印 NSLog(@"thread:%@", [NSThread currentThread]); });NSLog(@"haha");//后打印//死锁①dispatch_sync(dispatch_get_main_queue(), ^{ [NSThread sleepForTimeInterval:1.0f]; NSLog(@"thread:%@", [NSThread currentThread]); }); NSLog(@"haha");//造成死锁,haha永远不会打印//死锁②dispatch_queue_t serialQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);dispatch_sync(serialQueue, ^{ NSLog(@"thread1:%@", [NSThread currentThread]); dispatch_sync(serialQueue, ^{ NSLog(@"thread2:%@", [NSThread currentThread]);//造成死锁,thread2永远不会打印 }); });
- 异步任务:添加一个任务后不需要等待任务执行完成
//异步任务dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [NSThread sleepForTimeInterval:1.0f]; //后打印 NSLog(@"thread:%@", [NSThread currentThread]); });NSLog(@"haha");//先打印
其他用法
- dispatch_after:延迟指定的时间后,将任务添加到指定的队列中
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0f * NSEC_PER_SEC));dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"haha");});
- dispatch_group:将多个任务或队列归为一组,在这组的所有任务都执行完之后再执行后面的操作
- dispatch_group_async函数:创建一个指定队列中的异步任务,并将其添加到指定组中
- dispatch_group_notify函数:指定组中所有任务都执行完后,会执行该函数所指定的的任务
- dispatch_group_wait函数:阻塞当前线程,等待group中所有任务执行完毕
//使用dispatch_group_notifydispatch_group_t group = dispatch_group_create();dispatch_queue_t concurrentQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"1"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"2"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"3"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"4"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_notify(group, concurrentQueue, ^{ NSLog(@"5");//"1234"全部打印后,才会打印5});//使用dispatch_group_waitdispatch_group_t group = dispatch_group_create();dispatch_queue_t concurrentQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"1"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"2"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"3"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_async(group, concurrentQueue, ^{ NSLog(@"4"); [NSThread sleepForTimeInterval:1.0f];});dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"haha");//"dispatch_group_wait"会阻塞线程,所有haha会在"1234"之后打印
- diapatch_once:执行一次
- dispatch_apply:按照指定的次数将指定的Block追加到指定的DispatchQueue中,并等待全部处理执行结束
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t t) { NSLog(@"%zu", t); [NSThread sleepForTimeInterval:1.0f];});NSLog(@"haha");//等待dispatch_apply中的所有任务都执行完之后才会带引"haha"
- dispatch_suspend / dispatch_resume
- dispatch_suspend:挂起指定的队列
- dispatch_resume:恢复指定的队列
- Dispatch Semaphore:信号量,用于排他控制
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);for (int i = 0; i < 10; i++) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //排他,同时只能有一个线程进入这个代码块,相当于锁 NSLog(@"end wait, result:%ld", result); [NSThread sleepForTimeInterval:1.0f]; dispatch_semaphore_signal(semaphore); });}
NSOperation
基本用法
- NSBlockOperation:以Block的形式定义任务
@interface testOperation ()@property (nonatomic, strong) NSOperationQueue * queue;@end@implementation testOperation- (void)startTest { //创建操作 NSOperation * oper1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"test block operation1, current thread:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f]; }]; NSOperation * oper2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"test block operation2, current thread:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f]; }]; NSOperation * oper3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"test block operation3, current thread:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f]; }]; NSOperation * oper4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"test block operation4, current thread:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f]; }]; self.queue = [[NSOperationQueue alloc] init]; //将操作加入队列中,操作就会在队列中并发执行,NSOperationQueue默认是并发队列 [self.queue addOperation:oper1]; [self.queue addOperation:oper2]; [self.queue addOperation:oper3]; [self.queue addOperation:oper4];}@end
- NSInvocationOperation
@interface testOperation ()@property (nonatomic, strong) NSOperationQueue * queue;@end@implementation testOperation- (void)startTest { NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:@selector(oper1Fun:andObj2:)]; NSInvocation * invo = [NSInvocation invocationWithMethodSignature:sig]; [invo setTarget:self]; [invo setSelector:@selector(oper1Fun:andObj2:)]; NSString * arg1 = @"haha"; NSString * arg2 = @"oooo"; [invo setArgument:&arg1 atIndex:2]; [invo setArgument:&arg2 atIndex:3]; NSOperation * oper1 = [[NSInvocationOperation alloc] initWithInvocation:invo]; NSOperation * oper2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(oper2Fun) object:nil]; self.queue = [[NSOperationQueue alloc] init]; [self.queue addOperation:oper1]; [self.queue addOperation:oper2];}- (void)oper1Fun:(id)obj1 andObj2:(id)obj2 { NSLog(@"test invocation operation1, current thread:%@, obj1:%@, obj2:%@", [NSThread currentThread], obj1, obj2); [NSThread sleepForTimeInterval:1.0f];}- (void)oper2Fun { NSLog(@"test invocation operation2, current thread:%@", [NSThread currentThread]);}@end
- 继承NSOperation,重写main方法
@interface MyOperation : NSOperation@end@implementation MyOperation- (void)main { NSLog(@"MyOperation, current thread:%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:1.0f];}@end//main.mNSOperationQueue * queue = [[NSOperationQueue alloc] init];MyOperation * op1 = [[MyOperation alloc] init];MyOperation * op2 = [[MyOperation alloc] init];MyOperation * op3 = [[MyOperation alloc] init];MyOperation * op4 = [[MyOperation alloc] init];MyOperation * op5 = [[MyOperation alloc] init];MyOperation * op6 = [[MyOperation alloc] init];[queue addOperation:op1];[queue addOperation:op2];[queue addOperation:op3];[queue addOperation:op4];[queue addOperation:op5];[queue addOperation:op6];
其他用法
- 设置最大并发数
self.queue.maxConcurrentOperationCount = 3;
- 设置操作之间的依赖关系
[oper2 addDependency:oper1];//oper2依赖于oper1,即必须oper1执行完之后才能执行oper2
- 手动管理NSOperation
- 运行一个Operation:
- (void)start;
默认的start方法会直接进行一些异常判断,然后直接调用- (void)main;
- 取消一个Operation:
- (void)cancel;
调用cancel方法并不会停止操作的执行,这取决于main方法中对cancel的处理。如果在main方法中没有对cancel进行处理,发送cancel消息是没有任何效果的
- 运行一个Operation:
//MyOperation.m@implementation MyOperation- (void)start { [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];}- (void)main { NSInteger index = 0; while (1) { NSLog(@"current thread:%@, index:%ld", [NSThread currentThread], index++); if (self.isCancelled) { NSLog(@"cancel"); return; } [NSThread sleepForTimeInterval:1.0f]; }}@end//main.mMyOperation * op1 = [[MyOperation alloc] init];[op1 start];[NSThread sleepForTimeInterval:3.0f];[op1 cancel];
0 0
- iOS中的多线程编程
- NSOperation和NSOperationQueue在iOS多线程编程中的使用
- iOS多线程编程指南
- IOS多线程编程指南
- [ios]多线程编程指南
- ios多线程编程
- iOS多线程编程
- iOS多线程编程
- iOS多线程编程指南
- iOS多线程编程
- IOS多线程编程
- iOS多线程编程
- IOS多线程编程指南
- iOS多线程编程
- 浅谈iOS多线程编程
- IOS多线程编程
- iOS中多线程编程
- iOS多线程编程技术
- Fragment与Fragment之间的数据通信
- 项目1.4在构造函数中使用参数初始化表对数据成员初始化
- 第四周项目1-三角形类的构造函数-有默认参数的构造函数
- 消息总线扩展之面向消息的数据集成
- POJ 1696 || Space Ant (叉积,凸包变形题
- iOS中的多线程编程
- 统计n!中0的个数
- fetal:remote origin already exits
- 设计模式之--Abstract Factory模式
- ConcurrentHashMap内部原理分析
- 第5周项目4-静态成员应用
- 邻接表的两种模拟写法
- ORA-12541:TNS:无监听程序
- 步步为营_Android开发课[9]_Handle学习