概念:
//什么是进程?
//1.进程是指在系统中正在运行的一个应用程序//2.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内
//什么是线程?
//1.1个进程想要执行任务,必须得有线程(每个进程至少要有1条线程)
//2.线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行
//什么是多线程
//1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同任务
//多线程原理
//同一时间,CPU只能处理一条线程,只有一条线程在工作(执行)。多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
//如果线程非常非常多,会发生么情况?
//CPU会在n多线程之间调度,CPU会累死,消耗大量的CPU资源
//多线程的优点
//1.能适当提高程序的执行效率
//2.能适当提高资源利用率(CPU,内存利用率)
//多线程的缺点
//1.开启大量的线程,占用大量的内存空间,降低程序的性能
//2.线程越多,CPU在调度线程上的开销就越大
//3.程序设计更加复杂,比如线程之间的通信,线程的资源共享
//什么是主线程
//一个IOS程序运行后,默认会开启一条线程,成为“主线程”或“UI线程”
//主线程的主要作用
//1.显示\刷新UI界面
//2.处理UI事件(比如点击事件,滑动事件,拖拽事件等)
//主线程的使用注意
//1.别将比较耗时的操作放到主线程中
//2.耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验
//IOS中多线程的实现方案
//1.NSThread
//使用起来更加面向对象
//简单易用,可直接操作线程对象
//OC语言
//程序猿管理线程的生命周期
//偶尔使用 使用里面的个别方法
//
//2.GCD
//意在代替NSThread等线程技术
//充分利用设备的多核
//C语言
//自动管理线程的生命周期
//经常使用
//
//3.NSOperation
//基于GCD(底层是GCD)
//比GCD多了一些简单实用的功能
//实用更加面向对象
//自动管理线程的生命周期
//经常使用
1.NSThread
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UISwitch *switchButton = [[UISwitch alloc] initWithFrame:CGRectMake(0, 200, 70, 30)];
[self.view addSubview:switchButton];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 250, 320, 100)];
textView.editable = NO;
[textView setFont:[UIFont systemFontOfSize:30]];
[textView setText:@"nnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsaf"];
[self.view addSubview:textView];
}
- (void)loadData:(NSString *)str
{
//获取当前线程
NSLog(@"下载东西 ----- %@",[NSThread currentThread]);
//获取主线程
NSLog(@"拿到主线程 ---- %@",[NSThread mainThread]);
NSLog(@"str --- %@",str);
// //睡眠3秒
// [NSThread sleepForTimeInterval:3];
//睡眠到一个NSDate为止
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3];
[NSThread sleepUntilDate:date];
for (int i=0; i<10000; i++) {
NSLog(@"------------ %d",i);
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self createThread1];
}
//穿件线程方法3 隐式创建线程
- (void)createThread3
{
//不会创建线程
// [self performSelector:@selector(loadData:) withObject:@"performSelector"];
[self performSelectorInBackground:@selector(loadData:) withObject:@"performSelectorInBackground"];
}
//创建线程方法2 创建线程自动启动
- (void)createThread2
{
[NSThread detachNewThreadSelector:@selector(loadData:) toTarget:self withObject:@"detachNewThreadSelector"];
}
//创建线程方法1 创建线程然后启动线程
- (void)createThread1
{
//创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData:) object:@"NSThread"];
thread.name = @"下载线程";
//启动线程
[thread start];
}
2.GCD
@interface ViewController ()
{
UIImageView *_imageView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
[_imageView setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:_imageView];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//创建队列组
dispatch_group_t group = dispatch_group_create();
//获得全局并发队列
dispatch_queue_t globalConCurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
__block UIImage *image1=nil;
__block UIImage *image2=nil;
//下载图片1
dispatch_group_async(group, globalConCurrentQueue, ^{
NSLog(@"_____%@",[NSThread currentThread]);
NSURL *url1 = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/image/pic/item/8718367adab44aed3eb376e9b11c8701a18bfb3a.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
NSLog(@"data1 %@",data1);
image1 = [UIImage imageWithData:data1];
});
//下载图片2
dispatch_group_async(group, globalConCurrentQueue,^{
NSLog(@"_____%@",[NSThread currentThread]);
NSURL *url2 = [NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
NSLog(@"data2 %@", data2);
image2 = [UIImage imageWithData:data2];
});
//3.合并图片
dispatch_group_notify(group, globalConCurrentQueue, ^{
//开启一个位图上下文
UIGraphicsBeginImageContext(image1.size);
//绘制图片1
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
//绘制图片2
[image2 drawInRect:CGRectMake(image1.size.width-image2.size.width*0.4, image1.size.height-image2.size.height*0.4, image2.size.width*0.4, image2.size.height*0.4)];
//得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
//结束上下文
UIGraphicsEndImageContext();
//回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
[_imageView setImage:fullImage];
[_imageView setFrame:CGRectMake(0, 0, image1.size.width*0.4, image1.size.height*0.4)];
});
});
}
- (void)test1
{
//获得全局并发队列
dispatch_queue_t globalConCurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalConCurrentQueue, ^{
//1.下载图片1
NSURL *url1 = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/image/pic/item/8718367adab44aed3eb376e9b11c8701a18bfb3a.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
UIImage *image1 = [UIImage imageWithData:data1];
//2.下载图片2
NSURL *url2 = [NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
UIImage *image2 = [UIImage imageWithData:data2];
NSLog(@"image1 %@ image2 %@",image1,image2);
//3.合并图片
//开启一个位图上下文
UIGraphicsBeginImageContext(image1.size);
//绘制图片1
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
//绘制图片2
[image2 drawInRect:CGRectMake(image1.size.width-image2.size.width*0.4, image1.size.height-image2.size.height*0.4, image2.size.width*0.4, image2.size.height*0.4)];
//得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
//结束上下文
UIGraphicsEndImageContext();
//回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
[_imageView setImage:fullImage];
[_imageView setFrame:CGRectMake(0, 0, image1.size.width*0.4, image1.size.height*0.4)];
});
});
}
3.NSOperation
#import "ViewController.h"
@interface ViewController ()<UITableViewDelegate>
{
UIImageView *_imageView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
[_imageView setBackgroundColor:[UIColor blueColor]];
[self.view addSubview:_imageView];
[self baseUse2];
}
- (void)baseUse3
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
//1.异步下载图片
NSString *urlString = @"http://f.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd540153bf853da81cb39db3d7c.jpg";
NSURL *imageUrl = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [UIImage imageWithData:imageData];
// [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>]
// dispatch_async(dispatch_get_main_queue(), <#^(void)block#>)
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
[_imageView setImage:image];
}];
}];
}
- (void)baseUse2
{
//1.创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//设置最大并发数
queue.maxConcurrentOperationCount = 2;
//2.添加操作到队列中 自动执行任务 并发
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片1----%@",[NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片2 ----%@",[NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片3 ----%@",[NSThread currentThread]);
}];
NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片4 ----%@",[NSThread currentThread]);
}];
//设置依赖
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
[operation4 addDependency:operation3];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
[queue addOperation:operation4];
[queue addOperationWithBlock:^{
NSLog(@"下载图片5 ----%@",[NSThread currentThread]);
}];
}
- (void)baseUse1
{
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片1--------%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"下载图片2--------%@",[NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"下载图片3--------%@",[NSThread currentThread]);
}];
[blockOperation setCompletionBlock:^{
NSLog(@"操作结束");
}];
[blockOperation start];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
// [queue cancelAllOperations];//取消队列中的所有任务(不可恢复)
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// [queue setSuspended:YES];//暂停队列中的所有任务
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// [queue setSuspended:NO];//恢复队列中的所有任务
}
@end
多线程总结:
一,线程注意点
1.不要同时开太多线程,(1-3个线程即可,不要超过5个)
2.线程概念
1》主线程:UI线程 显示 刷新UI界面 处理UI控件的事件
2》子线程:后台线程,异步线程
3.不要把耗时操作放在主线程,要放在子线程中执行
二,NSThread
1.创建和启动线程的3种方法
1》先创建 后启动
//创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData:) object:nil];
//启动线程
[thread start];
2》创建完自动启动
[NSThread detachNewThreadSelector:@selector(loadData:) toTarget:self withObject:nil];
3》隐式创建自动启动
[self performSelectorInBackground:@selector(loadData:) withObject:nil];
2.常见方法
1》获得当前线程
+ (NSThread *)currentThread;
2》获得主线程
+ (NSThread *)mainThread;
3》睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4》设置线程名字
- (void)setName:(NSString *)n;
- (NSString *)name;
三,线程同步
1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题---
2.实现:给代码加一个互斥锁(同步锁)
@synchronized(self){
//被锁住的代码块
}
四,GCD
1.任务和队列
1》任务:需要执行什么操作 用block来封装任务
同步执行 不具备开启线程的能力
dispatch_sync
异步执行 具备开启新线程的能力
dispatch_async
2》队列:存放任务
全局并发队列:可以让任务并发执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
自己创建的串行队列:让任务一个接着一个执行
dispatch_queue_t queue = dispatch_queue_create("SerialQueue", DISPATCH_QUEUE_SERIAL);
主队列:让任务在主线程中执行
dispatch_queue_t queue = dispatch_get_main_queue();
2.常见任务和队列组合
1》dispatch_async + 全局并发队列
2》dispatch_async + 自定义串行队列
3》dispatch_async + 主队列
3.延迟执行
1》- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
2》dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// --------dosomething-------
});
五,NSOperation和NSOperationQueue
1.队列的类型
1》主队列
[NSOperationQueue mainQueue];
添加到“主队列”中的操作,都会放到主线程中执行
2》非主队列
[[NSOperationQueue alloc] init];
添加到“非主队列”中操作,都会放到子线程中执行
2.队列添加任务
- (void)addOperation:(NSOperation*)op;
- (void)addOperationWithBlock:(void (^)(void))block;
3.常见用法
1》最大并发数
maxConcurrentOperationCount
2》设置依赖关系解除依赖关系
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
4.队列其他操作
1》取消所有操作
[queue cancelAllOperations];//取消队列中的所有任务(不可恢复)
2》暂停所有操作
[queue setSuspended:YES];//暂停队列中的所有任务
3》恢复所有操作
[queue setSuspended:NO];//恢复队列中的所有任务
六,从其他线程回到主线程的方式
1》perform
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>]
2》dispatch
dispatch_async(dispatch_get_main_q<#^(void)block#>ueue(), )
3》NSOperationQueue
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
---dosomething----
}];