ios 多线程
IOS多线实现有4种方式,分别是pthread,NSThread、GCD、NSOPeration,
其中,pthread是使用C语言写的,开发者需要自己负责内存管理,适用于unix/linux/windows等系统,具备跨平台可移植,但是使用难度大,几乎不被使用;
NSThread是使用OC语言开发的,使用面向对象,简单易用,可以直接操作线程对象,需要开发者管理内存,偶偶使用;
GCD:旨在替代NSTread线程技术,充分利用设备的多核,基于C的底层Api,是自动内存管理的,经常使用;
NSOperation:是基于GCD实现的Objective-C API,比GCD多了一些更简单的使用功能,使用更加面向对象,自动内存管理,经常使用;
1.NSTread的使用,创建NSThread的方法有很多种,可以通过类方法和对象方法,也可以通过NSObject的分类方法;
-(void)createThreadByInit{
JYThreadManager* jy = [[JYThreadManager shareInstance] initWithTarget:self selector:@selector(msg1) object:nil];
[jy start]; // 这里需要发送start才能将线程对象加入线程池
}
-(void)createThreadByDetachNewThreadBlock{
// 默认创建完线程就加入了线程池
[JYThreadManager detachNewThreadWithBlock:^{
NSLog(@”block方式创建了对象”);
}];
}
-(void)createThreadByDetachNewThreadTargetBlock{
// 默认创建完线程就加入了线程池了
[JYThreadManager detachNewThreadSelector:@selector(msg2) toTarget:self withObject:nil];
}
-(void)msg1{
NSLog(@”对象创建了1”);
}
-(void)msg2{
NSLog(@”对象创建了2”);
}
2.NSOperation:它是一个抽象类,使用时通常是使用它的子类类进行实例化对象,NSInvocationOperation、NSBlockOperation,或者自定义子类来封装操作
NSOperationQueue:操作队列,将NSOperation放在其中进行操作,Nsoperation和NSOperationqueue都有一些属性,具体属性如下:
/**
nsoperation的属性
*/
-(void)operationPriority{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(method) object:nil];
[op setCompletionBlock:^{
NSLog(@”op执行完了”);
}];
[op start];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”op2:method执行了”);
}];
[op2 setCompletionBlock:^{
NSLog(@”op2执行完了”);
}];
[op2 start];
// [NSThread sleepForTimeInterval:3];
// [op cancel];
// [op start];
// [op waitUntilFinished];
// while (1) {
// if (op.isCancelled) {
// NSLog(@”队列取消了”);
// break;
// }else{
// if (op.isFinished) {
// NSLog(@”队列结束了”);
// break;
// }
// if (op.isExecuting) {
// NSLog(@”队列在执行”);
// }
// if (op.isReady) {
// NSLog(@”队列处于就绪状态”);
// }
// }
// }
}
-(void)method{
NSLog(@”op:method方法执行了”);
}
/**
队列的属性
*/
-(void)operationqueuePriority{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
self.queue = queue;
[queue addOperationWithBlock:^{
NSLog(@”队列操作1”);
[NSThread sleepForTimeInterval:3];
}];
[queue addOperationWithBlock:^{
NSLog(@”队列操作2”);
[NSThread sleepForTimeInterval:3];
}];
[queue addOperationWithBlock:^{
NSLog(@”队列操作3”);
[NSThread sleepForTimeInterval:3];
}];
[queue addOperationWithBlock:^{
NSLog(@”队列操作4”);
[NSThread sleepForTimeInterval:3];
}];
[queue addOperationWithBlock:^{
NSLog(@”队列操作5”);
[NSThread sleepForTimeInterval:3];
}];
[queue addOperationWithBlock:^{
NSLog(@”队列操作6”);
[NSThread sleepForTimeInterval:3];
}];
}
-(void)stop{
if (!self.queue.isSuspended) {
[self.queue setSuspended:YES];
NSLog(@”队列暂停了”);
}
}
-(void)continu{
if (self.queue.isSuspended) {
[self.queue setSuspended:NO];
NSLog(@”队列恢复了”);
}
}
-(void)cancel{
if (self.queue) {
[self.queue cancelAllOperations];
NSLog(@”队列取消了”);
}
}
注:一般地,使用多线程要考虑线程安全问题,在NSOperation中,线程安全通过加锁、同步、信号量来实现; 线程通信也是经常使用的,如我们将大量工作放在后台运行,运行完成后需要切到前台来更新UI,这时就会使用到多线程
3.GCD:Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并发任务。在 Mac OS X 10.6 雪豹中首次推出,也可在 iOS 4 及以上版本使用。
GCD的好处:1.可用于多核的并行运算;
2.GCD会自动利用更多的CPU内核;
3.GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程);
4.不需要开发者管理编写任何线程管理代码
GCD中两个核心概念:任务和队列
任务:需要在线程中执行的代码,GCD是放在block中的,任务执行有2个方式,分别是:同步执行,异步执行,这两种执行方式的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。
同步执行:添加任务到指定的队列中,在添加的任务执行结束前,会一直等待,直到队列任务完成之后再继续执行该任务
异步执行:添加任务到指定队列中,任务不会做任何等待,可以继续执行任务,可以在新的线程中执行任务,具备开启新线程的能力。异步执行虽然具备开启新线程的能力,但是并不一定会开启新线程,具体要根据任务所指定队列类型有关.
在GCD中有两种队列:串行队列和并发队列,两种的主要区别是任务执行顺序不同,开启线程数不同
串行队列中的任务是一个接一个地执行,并发队列中的任务可以同时并发执行。
GCD的使用:
-(void)sellTicketMethod{
// 创建一个并发队列, GCD有一种特殊的并发队列:全局队列 dispatch_get_global_queue获取
dispatch_queue_t queue = dispatch_queue_create(“北京站窗口”,DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
[self sellTicketAction];
});
// 创建另一个串行队列, GCD有一种特殊串行队列:主队列 dispatch_get_main_queue()获取,朱队列中的任务都会放到主线程中去执行
// dispatch_queue_t queue2 = dispatch_queue_create(“深圳站窗口”,DISPATCH_QUEUE_SERIAL);
// dispatch_sync(queue2, ^{
// [self sellTicketAction];
// });
}
-(void)sellTicketAction{
while (1) {
[self.lock lock]; // 上锁
NSLog(@”thread-name:%@”,[NSThread currentThread]);
if (self.ticketsCount > 0) {
self.ticketsCount –;
NSLog(@”出票成功, 剩余票数:%ld”,self.ticketsCount);
[self .lock unlock];
}else{
NSLog(@”余票不足, 剩余票数:%ld”,self.ticketsCount);
[self .lock unlock];
break;
}
}
}
/**
异步串串行
*/
- (void)asyncSerial {
NSLog(@”currentThread—%@”,[NSThread currentThread]); // 打印当前线程
NSLog(@”asyncSerial—begin”);
dispatch_queue_t queue = dispatch_queue_create(“net.bujige.testQueue”, DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”1—%@”,[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”2—%@”,[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”3—%@”,[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@”asyncSerial—end”);
}
/**
同步执行+主队列
*/
-(void)syncMain{
NSLog(@”——–begin:%@”,[NSThread currentThread]);
[NSThread detachNewThreadSelector:@selector(method) toTarget:self withObject:nil];
NSLog(@”——–end:%@”,[NSThread currentThread]);
}
-(void)method{
NSLog(@”currentThread—%@”,[NSThread currentThread]); // 打印当前线程
NSLog(@”syncMain—begin”);
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”1—%@”,[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”2—%@”,[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”3—%@”,[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@”syncMain—end”);
}
GCD的线程通信:
- (void)communication {
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(queue, ^{
// 异步追加任务
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”1—%@”,[NSThread currentThread]); // 打印当前线程
}
// 回到主线程
dispatch_async(mainQueue, ^{
// 追加在主线程中执行的任务
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@”2—%@”,[NSThread currentThread]); // 打印当前线程
});
});
}
/**
栅栏方法,用于将两组异步执行的工作分开,使得前面一组执行完成后开始执行下一组动作
*/
-(void)barrier {
dispatch_queue_t queue = dispatch_queue_create(“www.d4cc.com”, DISPATCH_QUEUE_CONCURRENT);
// 第一组(2个任务)
dispatch_async(queue, ^{
// 任务1
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@”1—%@”,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
// 任务2
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@”2—-%@”,[NSThread currentThread]);
}
});
dispatch_barrier_async(queue, ^{
// 追加任务 barrier
for (int i=0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@”barrier—-%@”,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
// 追加任务3
for (int i = 0; i< 2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@”3——-%@”,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
// 追加任务4
for (int i = 0; i< 2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@”4——-%@”,[NSThread currentThread]);
}
});
}
-(void)apply {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@”apply—-begin”);
dispatch_apply(6,queue, ^(size_t index) {
NSLog(@”%zd—-%@”,index,[NSThread currentThread]);
});
NSLog(@”apply—end”);
}
/**
使用队列组实现最终对队列的一起回顾
*/
-(void)dispatch_group{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
NSLog(@”任务开始执行”);
dispatch_group_async(group, queue, ^{
NSLog(@”任务组1”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组2”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组3”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组4”);
});
dispatch_group_notify(group, queue, ^{
NSLog(@”任务全部执行完了”);
});
}
/**
使用dispatch_group_wait来替代dispatch_group_notify实现最终回顾
*/
-(void)dispatch_group_wait{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
NSLog(@”任务开始执行”);
dispatch_group_async(group, queue, ^{
NSLog(@”任务组1”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组2”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组3”);
});
dispatch_group_async(group, queue, ^{
NSLog(@”任务组4”);
});
// dispatch_group_notify(group, queue, ^{
// NSLog(@”任务全部执行完了”);
// });
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@”任务全部执行完了”);
}
/**
使用dispatch_group_enter dispatch_group_leave代替dispatch_group_async()的执行
*/
-(void)dispatch_group_enter_leave{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@”任务1”);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@”任务2”);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@”任务3”);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@”任务4”);
dispatch_group_leave(group);
});
// 这里是否执行要依据group中是否存在未执行线程,如果还存在,就不会执行以下
dispatch_group_notify(group, queue, ^{
NSLog(@”全部执行完了”);
});
}
/**
使用信号量将异步转换为同步
*/
-(void)semaphoreSync{
NSLog(@”currentThread—%@”,[NSThread currentThread]);
NSLog(@”semaphore—-begin”);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block int number = 0;
dispatch_async(queue, ^{
// 追加任务1
[NSThread sleepForTimeInterval:2];
NSLog(@”1—-%@”,[NSThread currentThread]);
number = 100;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
NSLog(@”semaphore—end,number=%zd”,number);
}
参考:行走的少年郎链接:https://www.jianshu.com/p/2d57c72016c6