首先,我们先来了解一下什么是线程.
说到线程,就要区分线程和进程.一个正在运行的程序叫做一个进程.多进程,顾名思义,就是多个程序正在运行.而线程,指的是一个程序或者一个进程中的运行"通道".每个进程中都有一个或者多个线程,如果只有一个,我们叫它主线程,主线程主要负责的是用户能看得见的东西,比如刷新界面,添加控件.除了一个主线程,其余的都是子线程.子线程和主线程是相互独立的.子线程主要负责用户看不到的任务,比如数据加载,任务下载.
之所以会有主线程,子线程的区分,是因为有一些任务是不需要用户去一直等待的.比如图片的加载,在图片没有加载出来的情况下,我们是选择让用户去等待还是可以去执行其它的操作?显然,用户等待加载是不现实的,而主线程是顺序操作,所以在图片加载出来前是不会执行别的操作的,这个时候我们就需要子线程,就是单独创建一个和主线程不相关的线程,用这个子线程去加载图片,主线程则可以继续进行操作,等子线程加载完图片,再回到主线程来,提高了用户体验,但也会消耗一定的资源,所以不建议很多线程同时使用.
下面介绍几个添加子线程的方法.
(一)轻量级的线程 -- NSThread,可以开线程和终止线程.
// 创建一个线程,其实就是给他一个方法去执行
// 创建一个子线程专门打印
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(actionWhile)
object:nil];
// 开启这个线程
[thread start];
// 线程操作需注意:在主线程的时候,系统自动会添加了一个自动释放池,那么在开启子线程的时候,也要添加一个自动释放池
// 如果线程开的比较多,会造成代码比较乱,阅读性不高
// 一般方法中有自动释放池的基本上都是线程方法
actionWhile方法中就是子线程要去实现的方法
//
- (void)actionWhile
{
// 添加一个自动释放池
@autoreleasepool {
// 要实现的方法
}
}
(二)基类中开启线程
基类中也提供开启线程的类--NSOperation,这个类是个抽象类,没有具体功能,功能由NSBlockOperation,NSInvocationOperation实现,下面分别创建例子.
// 创建任务1
NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(invocation1) object:nil];
// 创建任务2
NSBlockOperation *blockOP2 = [NSBlockOperation blockOperationWithBlock:^{
// block块中就相当于添加的任务
[self blockOP2];
}];
// 创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 把任务添加进队列当中
// 注意:添加任务前要设置依赖关系
// 依赖性(串行)
[invocation addDependency:blockOP2];
[queue addOperation:invocation];
[queue addOperation:blockOP2];
// 设置最大并发数,一起开始,谁先结束不知道
queue.maxConcurrentOperationCount = 2;
下面再去实现相应的任务方法
// 实现任务一
- (void)invocation1
{
// 子线程中添加一个自动释放池
@autoreleasepool {
// 当前线程的信息[NSThread currentThread]
// [NSThread isMainThread]是否是主线程
// 打印出来的number是线程的个数,第几个线程
NSLog(@"%@ 是不是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
}
}
// 实现任务2
- (void)blockOP2
{
// 添加释放池
@autoreleasepool {
NSLog(@"%@ 是不是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
}
}
(三)GCD(Grand Central Dispatch),是苹果公司开发的技术,以优化应用程序支持多核心处理器和其他的对称多处理系统地系统.GCD属于函数级的多线程,性能更高,功能也更强大.
GCD分为串行队列和并行队列两种.
串行队列又分为两种:1是主线程中的串行队列,会顺序执行,并且都会在主线程中执行.2是自定义的串行队列,会单独创建一个子线程去执行这些任务,并且这些任务在子线程中也是顺序执行的.
// 1.主线程中的串行队列(主串队列)
// dispatch_queue GCD中表示一个队列
// 创建一个主队列,实际上就是把主线程取出来了
// dispatch_queue_t mainQueue = dispatch_get_main_queue();
// // 添加任务
// // 参数1:要添加任务的队列
// // 参数2:要执行的任务
// dispatch_async(mainQueue, ^{
// NSLog(@"第一个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
// });
// // 任务2
// dispatch_async(mainQueue, ^{
// NSLog(@"第二个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
// });
// dispatch_async(mainQueue, ^{
// NSLog(@"第三个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
// });
// 2.自定义的串行队列
// 创建一个自定义的线程队列
// 参数一:队列的标示符
// 参数二:队列的执行类型(串|并)
// DISPATCH_QUEUE_SERIAL串行
dispatch_queue_t myQueue = dispatch_queue_create("com.ys.myQueue", DISPATCH_QUEUE_SERIAL);
// 添加任务
dispatch_async(myQueue, ^{
NSLog(@"自定义第一个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
});
dispatch_async(myQueue, ^{
NSLog(@"自定义第二个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
});
dispatch_async(myQueue, ^{
NSLog(@"自定义第三个任务,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
});
// 延迟回到主线程执行
// delayInSeconds填延迟几秒
// 延迟几秒后回到主线程执行任务
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
NSLog(@"延迟5秒执行");
NSLog(@"延迟5秒后,所在线程:%@, 是否是主线程:%d", [NSThread currentThread], [NSThread
currentThread].isMainThread);
});
并行队列也分为两种:1是全局队列,用
dispatch_get_global_queue去调用的,根据优先级访问队列.2是自定义并行队列,同时去执行,但谁先结束是不确定的.
并行队列是在除了主线程外创建多个子线程(有几个任务创建几个子线程),然后并发执行.大家可以通过其打印的结果细细体会.
// 1.全局队列
// 参数1;队列的执行顺序,默认的
// 参数2:预留参数,一般填0
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async(queue, ^{
// for (int i = 0; i < 10; i++) {
// NSLog(@"第一个任务,所在线程:%@, 是否是主线程:%d, %d", [NSThread currentThread],
[NSThread currentThread].isMainThread,i);
// }
// });
//
// dispatch_async(queue, ^{
// for (int i = 10; i < 20; i++) {
// NSLog(@"第二个任务,所在线程:%@, 是否是主线程:%d, %d", [NSThread currentThread],
[NSThread currentThread].isMainThread,i);
// }
// });
//
// dispatch_async(queue, ^{
// for (int i = 20; i < 30; i++) {
// NSLog(@"第三个任务,所在线程:%@, 是否是主线程:%d, %d", [NSThread currentThread],
[NSThread currentThread].isMainThread, i);
// }
// });
// 2.自定义并行队列
dispatch_queue_t myQueue = dispatch_queue_create("com.sy.king", DISPATCH_QUEUE_CONCURRENT);
// 添加任务
dispatch_async(myQueue, ^{
for (int i = 0; i < 10; i++) {
NSLog(@"第一个任务,所在线程:%@, 是否是主线程:%d, ----%d", [NSThread currentThread],
[NSThread currentThread].isMainThread,i);
}
});
dispatch_async(myQueue, ^{
for (int i = 10; i < 20; i++) {
NSLog(@"第二个任务,所在线程:%@, 是否是主线程:%d, ----%d",
[NSThread currentThread], [NSThread currentThread].isMainThread,i);
}
});
dispatch_async(myQueue, ^{
for (int i = 20; i < 30; i++) {
NSLog(@"第三个任务,所在线程:%@, 是否是主线程:%d, ----%d", [NSThread currentThread],
[NSThread currentThread].isMainThread, i);
}
});