// 获取主线程
NSThread *thread = [NSThread mainThread];
// 判断一个线程是否为主线程
BOOL isMainThread = [NSThread isMainThread];
//获取当前线程
NSThread *currentThread = [NSThread currentThread];
1.线程是CPU调用(执行任务)的最小单位。
2.进程是CPU分配资源和调度的单位。
3.一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程。
4.同一个进程内的线程共享进程的资源。
7.多线程的并发原理:
一个程序可以有多个进程,一个进程又可以开启多条线程,但至少会有一条线程,同一时刻,一条线程只能执行一个任务,一个cpu只能执行一条线程,多线程并发执行,其实是CPU在多条线程之间来回的切换,由于切换的速度非常快,就给我们造成了多条线程同时并发执行的假象.
8.多线程的优缺点:
优点:由于多线程可以达到将一些耗时操作放到主线程意外的子线程中去执行,这样在程序执行过程中就不会造成阻塞主线程的情况这样能够减少程序卡顿的现象,同时能够提高CPU的资源的利用率.
缺点:开启线程是有花销的,1.占用宝贵的栈存储空间,一个子线程占用512K,一个主线程占用1M,2.创建一个线程要花费90毫秒的时间,
所以我们在开发中,不能过多的开启线程,一般开启3到5条.
9.多线程的实现方案:
1.pthread
线程创建:
// 创建线程对象
pthread_t thread;
//2.创建线程
/*
第一个参数:线程对象
第二个参数:线程属性
第三个参数:指向函数的指针
第四个参数:函数的{参数}
*/
pthread_create(&thread, NULL, run, NULL);
void *run(void *param){
NSLog(@"%@",[NSThread currentThread]);
return NULL;
}
2.NSThread
NSTread线程的三种方式
// NSTread创建线程的三种方式
// 第一种 创建线程
NSThread *thraed = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 第二种 分离子线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
// 第三种 开启后台线程
[self performSelectorInBackground:@selector(run) withObject:nil];
}
- (void)run
{
NSLog(@"%@",[NSThread currentThread]);
}
3.GCD
//同步函数+串行队列:不会开线程,串行执行
-(void)syncSerial
{
//1.创建串行队列
/*
第一个参数:C语言的字符串 标签,名称
第二个参数:封装任务的block
DISPATCH_QUEUE_SERIAL :串行
DISPATCH_QUEUE_Concurrent:并发
*/
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
//2.使用同步函数封装任务并且把任务添加到队列中
/*
第一个参数:队列
第二个参数:封装任务的block
*/
dispatch_sync(queue, ^{
NSLog(@"1-----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@",[NSThread currentThread]);
});
}
注意:异步函数并发队列的情况下,可以开启多条线程,
异步函数串行队列的情况下,只能开启一条线程,
异步函数主队列的情况下,不会开启线程,
// 主队列:系统提供的一个串行队列 获取方法
// 注意:同步函数主队列的情况下会造成程序死锁
// 同步函数的特点: 1.在当前线程中执行,不具备开线程的能力
// 2.要求立刻马上执行
dispatch_queue_t queue = dispatch_get_main_queue();
// 把任务添加到主队列中
dispatch_async(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
});
// 全局并发队列,系统提供的
// 获取全局并发队列
dispatch_queue_t queue1 = dispatch_get_global_queue(0, 0);
// 把任务添加到队列中
dispatch_async(queue1, ^{
NSLog(@"%@",[NSThread currentThread]);
});
同步函数其他任何情况下,不会开启新的线程
4.线程的状态
线程主要有:创建/就绪/运行/阻塞/死亡 5⃣️种状态
// 控制线程的状态
// 启动线程 调用
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(value) object:nil];
[thread start];
// 阻塞线程
[NSThread sleepForTimeInterval:2];
[NSThread sleepUntilDate:[NSData data]];
// 强制停止线程,也就是进入死亡状态
[NSThread exit];
4.NSOpreation
// 两种队列
// 1.主队列 串行队列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
// 2.非主队列 并发队列
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
/*
三个子类
1.NSInvocationOperation 参数:object是方法@selector(run)中要传的参数
2.NSBlockOperation
3.继承NSOperation,然后重写main方法,把操作封装在main方法中
*/
// 使用第一个子类创建一个操作
// 在不添加到非主队列的并发队列中的情况下,在主线程执行
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// 使用第二个子类创建一个操作
// 在不添加到非主队列的并发队列中的情况下,在主线程执行
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
// 追加额外的任务 在不添加到非主队列的并发队列中的情况下,此任务在子线程执行
[blockOp addExecutionBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
// 使用第三个子类创建一个操作:第三个操作是继承NSOperation,然后重写main方法,把操作封装在main方法中
// 将操作添加到非主队列中 这个方法底层会调用[op start];
[queue1 addOperation:op];
// 将blockOp操作添加到主队列
[queue addOperation: blockOp];
}
10.GCD中常用的函数
1.延迟函数:
// 第一种延迟 GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]);
});
// 第二种延迟 ,定时器 NSTimer与CADisplayLink
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 此定时器使用时必须加入到mainRunLoop中,才会有用 ,此定时器是屏幕刷新后就调用,屏幕刷新频率60次/秒
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(run)];
// 将link添加到mainRunLoop
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 第三种延迟 :方法performSelector:afterDelay
[self performSelector:@selector(run) withObject:nil afterDelay:2 inModes:nil];
// 栅栏函数 ,栅栏函数对同步函数无效,并且当队列为全局并发队列时,栅栏函数也无效
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++");
});
3.一次性代码
// 一次性代码在整个程序过程中只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"%@",[NSThread mainThread]);
4.GCD中的迭代
//GCD中快速迭代
/*
第一个参数:要遍历的次数
第二个参数:队列(并发
第三个参数:size_t 索引
*/
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
5.队列组
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//3.下载图片1 // 异步队列组函数添加任务
dispatch_group_async(group, queue, ^{
NSURL *url = [NSURL URLWithString:@"http://img5.hao123.com/data/1_02d75d1d077f83a767fb530ac4a0b80d_510"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.image1 = [UIImage imageWithData:data];
NSLog(@"1-----%@",[NSThread currentThread]);
11.NSOperation中常用的属性和方法
主队列:串行[NSOperation mainQueue]
非主队列:同时具备了并发和串行的功能,默认是并发 [NSOperation alloc]init]
// 最大并发数:同一时间最多可以处理多少个操作
//设置设置队列是串行:maxConcurrentOperationCount = 1
//NSOperationQueueDefaultMaxConcurrentOperationCount = -1 默认是-1 表示不收限制
queue.maxConcurrentOperationCount = 3;
// 属性,susPended
- (IBAction)susPendBtnClick:(id)sender {
//suspended 暂停:当为YES的时候暂停,NO的时候表示恢复
//注意:暂停可以恢复的
//暂停不会暂停当前正在执行的任务,暂停的是下一个任务
if (self.queue.suspended) {
self.queue.suspended = NO;
}else
{
self.queue.suspended = YES;
}
}
- (IBAction)cancelBtnClick:(id)sender {
//取消是不可以恢复,取消功能不能取消正在执行的任务
[self.queue cancelAllOperations];
}
// 属性,isCancelled是一个BOOL值,当系统操作取消后,isCancelled的值会变为YES,常用来结束正在执行的操作
//判断当前操作是否被取消,如果被取消那么就直接返回
if (self.isCancelled) {
return;
}
操作依赖和监听:
//添加操作依赖
//注意:不能设置循环依赖
[download1 addDependency:download2];
//添加操作监听
download2.completionBlock = ^{
NSLog(@"打电话给我-----%@",[NSThread currentThread]);
};
12.几种创建线程方式间的线程通信
// 1.NSThread
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 1.1 回到主线程
[thread performSelector:@selector(goBack) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
// 1.2 回到主线程
[thread performSelectorOnMainThread:@selector(goBack) withObject:nil waitUntilDone:YES];
// 2.GCD 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%s",__func__);
});
//4. NSOperation 回到主线程
NSBlockOperation *combie = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
[self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//4.回到主线程刷新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];