关于多线程,在编程中那是必不可少的,现在我们就好好梳理一下多线程.
在 iOS 中其实目前主要有3套多线程方案,他们分别是:
NSThread
GCD
NSOperation & NSOperationQueue
NSThread
NSThread是经过苹果封装后的,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。
它的生命周期还是需要我们手动管理,所以并不推荐使用
//多线程处理
-(void)manyThreadHandle
{
//方法1
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(makerun:) object:@"1"];
// 启动
[thread start];
//方法2 不用手动启动 自动启动
[NSThread detachNewThreadWithBlock:^{
NSLog(@"--方法2");
}];
//方法3 不用手动启动自动启动
[NSThread detachNewThreadSelector:@selector(makerun:) toTarget:self withObject:@"2"];
}
-(void)makerun:(NSThread*)thred
{
NSLog(@"多线程--%@",thred);
}
2017-08-30 16:01:24.863 runtimeTest[6579:165898] --方法2
2017-08-30 16:01:24.864 runtimeTest[6579:165897] 多线程--1
2017-08-30 16:01:24.864 runtimeTest[6579:165899] 多线程--2
在NSThread 中海油很多方法和属性
//取消线程
- (void)cancel;
//启动线程
- (void)start;
//判断某个线程的状态的属性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
//设置和获取线程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
//获取当前线程信息
+ (NSThread *)currentThread;
//获取主线程信息
+ (NSThread *)mainThread;
//使当前线程暂停一段时间,或者暂停到某个时刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
GCD 方法
GCD 这个名字是不是很霸气 ,天朝人都懂得.其实指的是Grand Central Dispatch(GCD)
GCD会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。这个方法比较实用简便,强烈推荐.
在GCD中,加入了两个非常重要的概念:任务和队列。
任务
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式:同步执行和异步执行,主要区别在于会不会阻塞当前线程,直到Block中的任务执行完毕!
同步执行:阻塞当前线程,不会开辟新的线程
异步执行:不会阻塞当前线,程会开辟新的线程
队列:用于存放任务。一共有两种队列,串行队列和并行队列。
放到串行队列的任务,GCD 会FIFO(先进先出)地取出来一个,执行一个,然后取下一个,这样一个一个的执行。简单说串行 就是单行车道 ,所有的车(任务)都只能按顺序走
放到并行队列的任务,GCD 也会FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。简单说并行 就是多条车道 ,所有的车(任务)都可以在对应车道上走,和隔壁车道没什么影响
主队列 任何需要刷新 UI 的工作都要在主队列执行
dispatch_queue_t queue = dispatch_get_main_queue();
自己创建队列
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", DISPATCH_QUEUE_CONCURRENT);
//全局并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
队列组
队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//多次使用队列组的方法执行任务, 只有异步方法
//执行3次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//执行10次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"group-03 - %@", [NSThread currentThread]);
}
});
//4.都完成后会自动通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
//运行结果
2017-08-30 16:21:36.201 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} 2017-08-30 16:21:36.201 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} 2017-08-30 16:21:36.206 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} 2017-08-30 16:21:36.209 runtimeTest[6843:174502] 完成 -{number = 1, name = main}
NSOperation和NSOperationQueue
NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解,有很多和GCD比较类似
NSOperation 和 NSOperationQueue分别对应 GCD 的任务 和 队列
NSOperation只是一个抽象类,所以不能封装任务它有 2 个子类用于封装任务。分别是:NSInvocationOperation和NSBlockOperation
当你新创建一个 Operation 后,需要手动的调用start方法来启动任务,它会默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其cancel方法即可。
//1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//2.开始执行
[operation start];
//1.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//添加多个Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//2.开始任务
[operation start];
2017-08-30 16:33:12.868 runtimeTest[7014:179819]{number = 1, name = main}
2017-08-30 16:33:12.869 runtimeTest[7014:179819] 第3次:{number = 1, name = main}
2017-08-30 16:33:12.869 runtimeTest[7014:179819] 第4次:{number = 1, name = main}
2017-08-30 16:33:12.868 runtimeTest[7014:179888] 第1次:{number = 4, name = (null)}
2017-08-30 16:33:12.868 runtimeTest[7014:179892] 第0次:{number = 3, name = (null)}
2017-08-30 16:33:12.869 runtimeTest[7014:179889] 第2次:{number = 5, name = (null)}
根据结果可以知道打印的顺序是乱的 这个也符合我们异步的任务执行情况
//1.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//2.开始任务
[operation start];
创建队列
//主队列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
//1.创建一个其他队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多个Block
for (NSInteger i = 0; i < 2; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//4.队列添加任务
[queue addOperation:operation];
2017-08-30 16:35:56.163 runtimeTest[7073:181494]{number = 3, name = (null)}
2017-08-30 16:35:56.163 runtimeTest[7073:181537] 第0次:{number = 4, name = (null)}
2017-08-30 16:35:56.163 runtimeTest[7073:181538] 第1次:{number = 5, name = (null)}
NSOperation有一个非常实用的功能,那就是添加依赖 和gcd中的队列组管理有点类似.有点啰嗦了,就先介绍这些吧,以后有时间会更新.










网友评论