2.单线程程序:程序只包含一个线程(主线程),线程中的代码按顺序执行,缺点:可能会造成主线程阻塞(有些任务耗时比较长)
3.多线程程序:程序中包含多个线程,线程是独立运行的,提高程序运行效率.
4.iOS开发中,所有跟UI有关的操作(绘制,刷新)都必须在主线程中完成.
5.子线程:主线程之外创建的新的线程
△.线程是可以设置优先级的
获取当前线程,判断是否是主线程的方法:
NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
先创建一个多线程测试环境:
-(void)cycle
{
//获取当前线程,判断是否是主线程
NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
int sum = 0;
for (int i=0; i<500; i++) {
sum += i;
// NSLog(@"%d",i);
}
// NSLog(@"%d",sum);
}
一 . 使用NSThread实现多线程 : 创建线程后,自动开启,无需手动调用开启
1.第一个参数:线程中需要执行的方法
2.第二个参数:执行方法的对象
3.第三个参数:传值
[NSThread detachNewThreadSelector:@selector(cycle) toTarget:self withObject:nil];
二 . 使用NSThread实现多线程 : 创建线程后,需要手动开启
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(cycle) object:nil];
[thread start];
三 . 使用NSObject类目方法实现多线程(用的比较多)
//隐式创建线程
[self performSelectorInBackground:@selector(cycle) withObject:nil];
//图片网址
NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
[self performSelectorInBackground:@selector(downloadImage:) withObject:url];
//在子线程中,同步连接下载图片
-(void)downloadImage:(NSString *)url
{
//在子线程中,使用同步方式下载图片. △备注:在子线程中,不要使用异步连接,会出现问题
/*
△注意事项:
1.子线程中没有自动释放池,需要手动添加
2.NSThread创建的子线程,默认情况下,任务执行完成后,线程被关闭,销毁
3.在子线程中,NSTimer默认情况下,不会执行.如果在子线程中使用NSTimer,必须开启runLoop,方法如下:
4.所有线程都有runLoop,主线程默认是开启状态,子线程默认是关闭状态
5.子线程开启runLoop后,runLoop不停止,线程无法关闭
*/
//获取当前线程的runLoop,并开启
// [[NSRunLoop currentRunLoop] run];
//获取当前线程的runLoop,并设定运行的时间
// [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
//获取当前线程,判断是否是主线程
NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
//同步下载图片
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
//将data转换成image对象
UIImage *image = [UIImage imageWithData:data];
//△注意:将image在主线程中进行显示.
// _imageView.image = image;//这句话位置不对,不能写在这里
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];//第三个参数:等待子线程任务执行完成,再回到主线程执行
//直接给imageView附图片
// [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
//在主线程中,将image显示在imageView上
-(void)showImage:(UIImage *)image
{
//获取当前线程,判断是否是主线程
NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
//参数image是从子线程中返回
_imageView.image = image;
}
四 . NSOperation 是一个操作类(抽象类),封装了需要执行的任务和数据. 一般不直接使用NSOperation,使用子类:NSInvocationOperation和NSBlockOperation
//操作对象封装了需要执行的任务和参数
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
//开始执行operation对象中封装的任务(方法)
//start在哪个线程中调用,operation对象中封装的方法就在哪个线程中执行
[operation start];
五 . block方法:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"当前线程 %@ ----- 是否是主线程:%d", [NSThread currentThread], [NSThread isMainThread]);
for (int i = 1; i < 500; i++) {
}
}];
[operation start];
六 . NSOperationQueue :
1.NSOperationQueue 操作队列(先进先出),可以管理多个操作对象.
2.NSOperationQueue 创建的多线程是可以重复使用的,是非脱离线程(线程中的任务完成后,线程进入睡眠状态,未被销毁;NSThread创建的线程是脱离线程)
3.NSOperationQueue 先加入队列的任务,先执行.(即"先进先出")
4.NSOperationQueue 控制的线程是并发执行的. 即:队列中的任务按照加入队列的顺序进行分派,但是下一个任务不用等待前一个任务完成再开始.多个任务可以同时执行,互不干扰. ("并发"相对的是"串行")
5.什么叫线程同步? 线程A执行结束后才能执行线程B
6.NSOperationQueue如何实现线程同步? 把最大并发数设置为1,即:每次只允许一个线程执行任务
7.队列下载
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
//设置最大并发数
queue.maxConcurrentOperationCount = 1;
//添加10个任务
for (int i=0; i<10; i++) {
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
//操作对象添加到队列里
[queue addOperation:operation];
}
七 . 使用GCD的队列实现串行(任务1执行后,任务2再执行) :
1.GCD队列类型:主队列,全局队列,自定义队列
2.GCD队列功能:串行,并发
3.能够实现串行的有两种队列:主队列和自定义串行队列
4.能够实现并发的有两种队列:全局队列和自定义并发队列
//串行队列 第一种实现:使用主队列
/*
dispatch_queue_t queue = dispatch_get_main_queue();
//向队列异步添加任务
dispatch_async(queue, ^{
NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
*/
//串行队列 第二种实现:使用自定义串行队列
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
//释放(注意:MRC下需要释放)
// dispatch_release(queue);
八 . GCD并发:任务A,B,C....按照进入队列顺序开始分派执行
//并发队列 第一种实现:全局队列
/*
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
*/
//并发队列 第二种实现:使用自定义并发队列
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
九 . GCD
//在子线程中建立同步连接下载图片(把任务添加到全局队列)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//建立同步连接下载图片
//图片网址
NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"同步连接下载图片,当前线程:%@",[NSThread currentThread]);
//在主线程中,显示下载的图像
dispatch_async(dispatch_get_main_queue(), ^{
_imageView.image = image;
NSLog(@"显示下载图片,当前线程:%@",[NSThread currentThread]);
});
});
十 . 总结:
1.耗费时间的两种方式:下载(跟网速有关)和处理数据
2. 任务 线程 方法
触发下载图片 主线程 didClick....Button
建立同步连接下载图片 子线程 download
3.
/*
1.每个进程至少包含一个线程,这个默认创建的线程被成为主线程
2.单线程程序:程序只包含一个线程(主线程),线程中的代码按顺序执行,缺点:可能会造成主线程阻塞(有些任务耗时比较长)
3.多线程程序:程序中包含多个线程,线程是独立运行的,提高程序运行效率.
4.iOS开发中,所有跟UI有关的操作(绘制,刷新)都必须在主线程中完成.
5.子线程:主线程之外创建的新的线程
△.线程是可以设置优先级的
*/
4.
/*
△注意事项:
1.子线程中没有自动释放池,需要手动添加
2.NSThread创建的子线程,默认情况下,任务执行完成后,线程被关闭,销毁
3.在子线程中,NSTimer默认情况下,不会执行.如果在子线程中使用NSTimer,必须开启runLoop,方法如下:
4.所有线程都有runLoop,主线程默认是开启状态,子线程默认是关闭状态
5.子线程开启runLoop后,runLoop不停止,线程无法关闭
*/
//获取当前线程的runLoop,并开启
// [[NSRunLoop currentRunLoop] run];
//获取当前线程的runLoop,并设定运行的时间
// [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
5.
/*
1.NSOperationQueue 操作队列(先进先出),可以管理多个操作对象.
2.NSOperationQueue 创建的多线程是可以重复使用的,是非脱离线程(线程中的任务完成后,线程进入睡眠状态,未被销毁;NSThread创建的线程是脱离线程)
3.NSOperationQueue 先加入队列的任务,先执行.(即"先进先出")
4.NSOperationQueue 控制的线程是并发执行的. 即:队列中的任务按照加入队列的顺序进行分派,但是下一个任务不用等待前一个任务完成再开始.多个任务可以同时执行,互不干扰. ("并发"相对的是"串行")
5.什么叫线程同步? 线程A执行结束后才能执行线程B
6.NSOperationQueue如何实现线程同步? 把最大并发数设置为1,即:每次只允许一个线程执行任务
7.队列下载
*/
6.
△.注意:GCD不等于多线程