iOS多线程主要有四种实现方式
Pthread
pthread是c语言的底层库对多线程调用的方式,具有跨平台的能力,但是一般在OC的编程中不使用。
NSThread
NSThread是对Pthread的一层封装,但是仍旧需要手动对线程进行管理,实际使用过程中可能造成线程的大量创建从而浪费内存。
NSThread的常用方法有:
创建线程
1 2 3 4 5 6
| // 需要显式掉用start函数 - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument; - (instancetype)initWithBlock:(void (^)(void))block; // 不需要显式调用start函数 + (void)detachNewThreadWithBlock:(void (^)(void))block; + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
|
启动线程
获取线程
1 2
| [NSThread mainThread]; [NSThread currentThread];
|
退出与取消线程
1 2
| [thread exit]; [thread cancel];
|
判断当前线程是否为主线程
睡眠
1
| + (void)sleepForTimeInterval:(NSTimeInterval)ti;
|
GCD - Grand Central Dispatch
GCD会自动利用CPU的多核,并自动管理线程的生命周期,主要用法如下:
创建队列
1 2
| dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr);
|
第一个参数表示该队列的名字,用于标识队列,第二个参数用于设置队列的属性,常见属性有:
DISPATCH_QUEUE_SERIAL - 队列内的所有操作串行进行;
DISPATCH_QUEUE_SERIAL_INACTIVE - 队列内操作串行,初始为不活跃状态,需dispatch_activate激活;
DISPATCH_QUEUE_CONCURRENT - 队列内操作串行;
DISPATCH_QUEUE_CONCURRENT_INACTIVE - 队列内操作串行,但是使用时需要激活;
获取内置队列
获取主线程所在队列
1
| dispatch_queue_main_t dispatch_get_main_queue(void);
|
获取其他内置队列
1
| dispatch_queue_global_t dispatch_get_global_queue(long identifier, unsigned long flags);
|
第一个参数表示队列的优先级,一般使用DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_HIGH,DISPATCH_QUEUE_PRIORITY_DEFAULT,DISPATCH_QUEUE_PRIORITY_LOW,DISPATCH_QUEUE_PRIORITY_BACKGROUND
第二个参数为预留参数,设为0即可。
同步
1
| void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
|
举例:
1 2 3 4 5
| dispatch_queue_t queue_sync = dispatch_queue_create("SyncQueue", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue_sync, ^{ sleep(2); NSLog(@"Sync"); });
|
注意当这段代码是在主线程内执行的时候,这里的queue不能是主线程所在的队列,如果是主线程的话,可能会造成死锁,因此一般不使用这个方法。
异步
1
| void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
|
举例:
1 2 3 4
| dispatch_async(queue, ^{ sleep(2); NSLog(@"1"); });
|
延迟操作
1
| void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
|
举例:
1 2 3 4
| dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)); dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"wait"); });
|
组操作
主要是可以使用dispatch_group_notify在完成一组任务之后进行一定的操作。
举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("groupQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_async(group, queue, ^{ sleep(2); NSLog(@"1"); }); dispatch_group_async(group, queue, ^{ sleep(2); NSLog(@"2"); }); dispatch_group_async(group, queue, ^{ sleep(3); [NSThread sleepForTimeInterval:3]; NSLog(@"3"); }); dispatch_group_notify(group, queue, ^{ NSLog(@"eee"); });
|
栅栏
1
| void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
|
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| - (void)viewDidLoad { [super viewDidLoad]; [self useGCDGroup]; NSLog(@"ViewDidLoad"); } - (void) useGCDGroup { dispatch_queue_t queue = dispatch_queue_create("groupQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ sleep(2); NSLog(@"1"); }); dispatch_async(queue, ^{ sleep(2); NSLog(@"2"); }); dispatch_barrier_sync(queue, ^{ NSLog(@"barrier"); }); dispatch_async(queue, ^{ sleep(4); NSLog(@"3"); }); dispatch_async(queue, ^{ sleep(2); NSLog(@"4"); }); }
|
barrier所对应的任务之前的任务都完成之后才会进行barrier的任务,然后才会进行barrier之后的任务。上述例子的输出结果为:
1 2 3 4 5 6
| 1 2 barrrier ViewDidLoad 4 3
|
其中1和2,3和4均有可能互换。
单例
用于保证block内代码只执行一次。
举例
1 2 3 4
| static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"dispatch"); });
|
信号量
1 2 3 4 5 6 7
| typedef NSObject<OS_dispatch_semaphore> *dispatch_semaphore_t; // 声明信号量 dispatch_semaphore_t dispatch_semaphore_create(long value); // 信号量 - 1, 相当于持有信号量 long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 信号量 + 1, 相当于释放信号量 long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
|
一般dispatch_semaphore_wait和dispatch_semaphore_signal成对使用,创建信号量时的参数即代表资源的持有量,如有多少个可用线程等。
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| dispatch_queue_t queue = dispatch_queue_create("useSemphore", DISPATCH_QUEUE_CONCURRENT); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ __block NSString *result = @""; dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"task 1 begins %@", [NSThread currentThread]); sleep(2); result = [result stringByAppendingFormat:@"ssssss"]; NSLog(@"task 1 ends"); dispatch_semaphore_signal(semaphore); }); dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"task 2 begins %@", [NSThread currentThread]); sleep(2); result = [result stringByAppendingFormat:@"eeeeee"]; NSLog(@"task 2 ends"); dispatch_semaphore_signal(semaphore); }); dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"result = %@", result); dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore); }); });
|
NSOperation
NSOperation是对GCD的又一层封装,一般有四种使用方式
NSInvocationOperation
1 2
| NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil]; [op start];
|
NSBlockOperation
1 2 3 4 5 6 7
| NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }]; [op addExecutionBlock:^{ NSLog(@"%@", [NSThread currentThread]); }]; [op start];
|
注意这里在初始化的时候定义的操作是在主线程上进行的,而addExecutionBlock时加的操作不是在主线程上进行的。
自定义NSOperation的子类
通过重写一些方法如main,来实现自定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @interface Wrapper : NSOperation @end @implementation Wrapper - (void)main { if (!self.isCancelled) { for (int i = 0; i < 3; i++) { sleep(2); NSLog(@"1 %@", [NSThread currentThread]); } } } @end // 使用 Wrapper *op = [[Wrapper alloc] init]; [op start];
|
NSOperationQueue
通过定义多个NSInvocationOperation和NSBlockOperation对象,并将它们放进一个NSOperationQueue类型的对象中,实现整个队列的统筹。同时,可以通过addDependency等方法实现依赖的先后操作顺序。
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 3; i++) { [NSThread sleepForTimeInterval:2]; NSLog(@"2 ---%@", [NSThread currentThread]); } }]; [op2 addExecutionBlock:^{ for (int i = 0; i < 3; i++) { [NSThread sleepForTimeInterval:2]; NSLog(@"3 ---%@", [NSThread currentThread]); } }]; NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil]; [op1 addDependency:op3]; [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; queue.maxConcurrentOperationCount = 1; // 设置最大并发操作数
|