一个线程被创建后会要放到线程池中才会被CPU 执行(有些会自动放到线程池中如creatNSThread2,有些需要手动放到线程池中如: creatNSThread1),
在线程池中的线程有三种状态 1,就绪状态(等待CPU执行), 2 ,运行状态(CPU正在执行) 3, 阻塞状态(有seelp或者线程锁)
/// 第一种 使用 NSThread开启线程的方法
-(void)creatNSThread1{
// NSThread 是一个对象,没alloc 一次开启一个线程
NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(run:)object:@"aaa"];
// 线程开启后需要 手动启动线程
// 生命周期不用程序员管理, 在线程任务结束后,系统会自动释放 thread
[thread start];
thread.name =@"new";
// 查看是否是主线程
// [thread isMainThread];
// [NSThread isMainThread];
}
/// 第二种 使用 NSThread开启线程的方法
-(void)creatNSThread2{
// 这个方式不需要手动开启, 也不需要管理生命周期,也没有返回不能像第一种方法一样给线程设置名字
[NSThreaddetachNewThreadSelector:@selector(run:)toTarget:selfwithObject:@"aaa"];
}
/// 第三种 使用 NSThread开启线程的方法 .隐式创建
-(void)creatNSThread3{
[selfperformSelectorInBackground:@selector(run:)withObject:self];
}
// 线程之间的通信
-(void)threadTalk{
// 从子线程回到主线程,多用于子线程中下载完毕,或者耗时操作完成,回到主线程更新UI,
// waitUntilDone, YES :等待主线程上操作完成, 在继续执行本线程的事件, NO:不等待
[selfperformSelectorOnMainThread:@selector(run:)withObject:selfwaitUntilDone:YES];
// 从本线程回到指定线程
[selfperformSelector:@selector(run:)onThread:[NSThreadmainThread] withObject:@""waitUntilDone:YES];
}
/*
线程锁(线程同步,多条线程在同一条线上顺序执行,多线程默认是异步的) :为了解决多线程中多个线程访问同一个资源的问题
例如 A B线程要对 C 资源做操作.
如果A先对 C操作,会先对C 加锁,在读取C的数据,经过线程A 对数据更改后,写入C 完成,解锁.
在加锁期间,线程B 不能访问到C的数据
*/
-(void)run1{
while (1) {
@synchronized (self) {
}
}
}
// 阻塞线程
[NSThreadsleepForTimeInterval:2];
// 强制退出线程
[NSThreadexit];
//===================================================
2 GCD
// GCD 主要任务和 队列
// 先进先出,后进后出原则
/*
1, GCD 有两种常见的执行任务的方式,
2, 队列 GCD有并发队列(具备开启多个线程的能力),串行队列(不具备开启线程的能力).
另:异步执行 选择的是并队列时,才具有开启线程的能力.
任务:决定具不具备开启线程的能力, 会不会阻塞当前线程
队列:影响的是 是否允许多个任务同时执行.
同步任务 +主队列 会锁死.一定不要这样写.
// 同步任务 +主队列 会锁死.一定不要这样写.
*/
-(void)creatGCD1{
// 第一中,同步执行任务的方式
dispatch_sync(dispatch_get_main_queue(), ^{
// 这里是要执行的任务
});
// 第二种,异步执行任务的方式
dispatch_async(dispatch_get_main_queue(), ^{
// 这里是要执行的任务
});
// 同步和异步的区别是:同步是在当前的线程中执行任务, 不开线程, 会阻塞当前线程 异步会开启新的线程, 不会阻塞当前线程
}
// 创建一个并发/串行队列 + 异步
-(void)creatGCD2{
// 第一个参数:队列的名称,标签第二个参数: 表明是串行(DISPATCH_QUEUE_SERIAL)还是并发(DISPATCH_QUEUE_CONCURRENT)
dispatch_queue_t queue =dispatch_queue_create("downLoad_image_queue",DISPATCH_QUEUE_CONCURRENT);
// dispatch_get_global_queue 是GCD提供的全局的并发队列
// 第一个参数表明优先级,第二个参数暂时没有用,
dispatch_queue_t golbai_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 将任务添加到刚刚创建的并发队列中.
dispatch_async(queue, ^{
// 会开启前子线程,
});
}
// 同步任务 +主队列 会锁死.一定不要这样写.
// 原因是 :主队列 是要顺序执行,同步任务, 任务是要先后执行,不能一起执行. 执行creatGCD3是在主队列中执行, 所以要从上往下依次执行,而同步任务也是顺序执行. 也就是说,主队列要求顺序执行 先执行nslog,而creatGCD3 在主队列中, nslog代码块也在主队列中,且 creatGCD3 在代码块之前,所以, 同步任务要求先把 creatGCD3执行完,才能执行 nslog, 导致程序锁死.
-(void)creatGCD3{
dispatch_sync(dispatch_get_main_queue(), ^{
// 这里的代码不会被执行,程序被锁死
NSLog(@"kkkkkkkkk");
});
}
/*
1. dispatch_barrier_async 栅栏.可以保证 先执行栅栏之前的任务, 然后在执行栅栏只会的任务,最后执行栅栏之后的任务.
注意异步任务不能加入到 全局队列,否则 栅栏就没用了.
2. 这是一个异步 + 并发队列,会先执行 end 在执行开启线程的工作.
*/
-(void)creatGCD4{
for (int i =0; i < 10; ++i) {
dispatch_queue_t queue =dispatch_queue_create("downImage_queue",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"111111");
});
dispatch_async(queue, ^{
NSLog(@"222222");
});
dispatch_barrier_async(queue, ^{
NSLog(@"barrier");
});
dispatch_async(queue, ^{
NSLog(@"333333");
});
dispatch_async(queue, ^{
NSLog(@"444444");
});
}
NSLog(@"----- end");
// 会先执行 打印 111111 222222 再打印 barrier 再打印 333333 和 444444
// 但是 111111, 222222并不一定按顺序执行. 333333 和 444444也不一定按顺序执行.
}
// 延迟操作
-(void)creatGCD5{
// 第一种
[selfperformSelector:@selector(run:)withObject:selfafterDelay:2.0];
// 第二种
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
}
// 单例
-(void)creatGCD6{
// 单例重写的是 +(instancetype)allocWithZone:(struct _NSZone *)zone 这个封的比较死
// 一般都是自己写一个 share方法,在内部 对[[ alloc] init]方法,做一次性执行
staticdispatch_once_t once;
dispatch_once(&once, ^{
// 这里的代码只会执行一次.
});
}
// 队列组, 要求 任务一,任务二 两个耗时操作都完成后,执行任务三
-(void)creatGCD7{
// 创建一个队列组
dispatch_group_t group =dispatch_group_create();
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_group_async(group, queue, ^{
for (int i =0; i < 100; ++i) {
NSLog(@"任务一");
}
});
dispatch_group_async(group, queue, ^{
for (int i =0; i < 100; ++i) {
NSLog(@"任务二");
}
});
dispatch_group_notify(group, queue, ^{
// 当任务组里的任务都完成了,会执行这里
NSLog(@"任务三");
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程做跟新UI操作
});
});
}
// ================================================
// NSOperation 是对GCD的封装,更加面向对象,主要靠 NSOpetation子类工作
/// NSBlockOperation 开启线程
-(void)creatNSOperation1{
NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
// 第一个任务会在主线程中执行
NSLog(@"任务一");
}];
[op addExecutionBlock:^{
// 当有两个或者连个以上的任务, 会开启子线程,但是第一个任务还是在主线程中执行.
NSLog(@"任务二");
}];
[op addExecutionBlock:^{
// 当有两个或者连个以上的任务, 会开启子线程,但是第一个任务还是在主线程中执行.
NSLog(@"任务三");
}];
}
/// NSOperationQueue + NSInvocationOperation 开启线程
-(void)creatNSOperation2{
// 创建队列
NSOperationQueue *queue = [NSOperationQueuenew];
NSOperationQueue *queue2 = [NSOperationQueuenew];
// 最大并发数最大并发数= 3 并不是说,在打印时 线程序号不会超过3,而是说在同一时间,最多给这个进程分配三个线程,有可能是刚好别的线程刚执行完, 立马拿来复用,
// 如果最大并发数 = 1. queue就变成串行队列了.
queue.maxConcurrentOperationCount =3;
// 挂起/暂停 YES : 挂起/暂停 NO : 取消挂起/取消暂停.
// 当有多个线程在执行,而用户要做一些比较好性能的操作时, 可以先将后台线程挂起,保证用户的流程度,当用户操作完成后, 在取消挂起,
// 但是当线程已经开始工作了, 不会被挂起,只有还没开始执行的线程会被挂起.
// queue.suspended = YES;
// 和queue.suspended的区别是cancelAllOperations是取消, 一旦取消就不能回复,需要重新add
// 和queue.suspended相同的是,cancelAllOperations也不能中途取消线程.
// 如果想要取消,线程,建议, 在每一个耗时操作后面自己添加一个判断,if (op.isCancelled == YES){ return; }
[queue cancelAllOperations];
// 创建任务
NSInvocationOperation *op1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run:)object:@"参数"];
NSInvocationOperation *op2 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run:)object:@"参数"];
NSInvocationOperation *op3 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run:)object:@"参数"];
NSInvocationOperation *op4 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run:)object:@"参数"];
NSBlockOperation *bq = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"任务一");
}];
[bq addExecutionBlock:^{
NSLog(@"任务二");
}];
// ------------------
// 监听任务完
[op4 setCompletionBlock:^{
// 这里还是在子线程中, 如果想更新UI要回到主线程中.
NSLog(@"任务4完成");
}];
// 设置依赖 op1会等待 op2, op3 执行完成后再执行,这个依赖可以跨队列依赖.不要循环依赖,
[op1 addDependency:op2];
[op1 addDependency:op3];
// --------------
// 只有将任务添加到队列中,任务才开始执行. 会开启子线程
[queue addOperation:op1];
[queue addOperation:op2];
[queue2 addOperation:op3];
[queue2 addOperation:op4];
// 将NSBlockOperation添加到任务中也能开启线程
[queue addOperation:bq];
}
// 线程间的通信
-(void)creatNSOperation3{
// 创建队列
NSOperationQueue *queue = [NSOperationQueuenew];
// 将任务添加到队列中
[queue addOperationWithBlock:^{
NSLog(@"做耗时操作");
// 耗时操作完后回到主线程.
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
NSLog(@"回到主线程");
}];
}];
}