- 进程和线程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位;线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位。线程的划分尺度小于进程,这使得多线程程序的并发性高;进程在执行时通常拥有独立的内存单元,而线程之间可以共享内存。使用多线程的编程通常能够带来更好的性能和用户体验,但是多线程的程序对于其他程序是不友好的,因为它可能占用了更多的CPU资源。当然,也不是线程越多,程序的性能就越好,因为线程之间的调度和切换也会浪费CPU时间。 - 串行和并行
当一个线程执行多个任务,会采用执行完一个再执行下一个的方式,这种执行任务的方式称为串行;多个线程分担多个任务,不同的任务同时执行,这种执行任务的方式称为并发。 - 同步和异步
同步是指当前一个任务未能完成时,后一个任务被阻塞;异步可以理解为不同的任务在不同的线程中执行,当开辟的子线程(工作线程)发生阻塞,主线程或其他线程不会受到影响。
说明:异步和并发的概念不完全相同,异步强调解决主线程阻塞的问题,而并发一般指子线程(工作线程)之间的关系,多个工作线程分担任务称为并发执行任务。
iOS开发中实现多线程的方式很多,包括:
- NSThread类:线程,此种方式是轻量级的线程机制,但需要自行管理线程的生命周期,线程同步等问题,同步锁会产生系统开销。
-
NSThread类:
线程,此种方式是轻量级的线程机制,但需要自行管理线程的生命周期,线程同步等问题,同步锁会产生系统开销。1.创建线程的三种方式:
//第一种创建方法
//第一个参数 执行线程的对象
//第二个参数 选择器
//第三个参数 传入的参数
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
//标记执行某一线程任务时的线程名字
thread.name = @"线程1";
//开启线程
[thread start];//第二种方法:类方法创建 【不返回任何数据类型】
[NSThread detachNewThreadSelector:@selector(run1:) toTarget:self withObject:@"33333"];//第三种方法:创建一个在后台的线程
[self performSelectorInBackground:@selector(run2) withObject:nil];
2.给线程加锁的三种方式
1)lock三个步骤:
//第一步:初始化一个锁的对象;
//锁是为了保障访问同一数据时 数据的安全性
_lock = [[NSLock alloc] init];
//第二步:给子线程加锁,不允许其它线程访问;
[_lock lock];
//第三部:子线程结束,给子线程解锁;允许其它线程访问;
[_lock unlock];
2)sychronized方法: 【将子线程要执行的操作写在大括号中】
//nonatomic非原子性 atomic 原子性(对同一时间访问的对象进行保护)
//相比于lock 而言,它只能锁住一次,不能重复加锁
//一旦锁住则知道线程完毕才允许另一个线程访问
@synchronized (self) 【这个方法直接写在子线程的实现方法中】
{
}
3)condition方法三个步骤:【和lock类似,但是多了暂停功能】
初始化
_condition = [[NSCondition alloc] init];
上锁
//condition上锁和lock相似
[_condition lock];
解锁
[_condition unlock];
condition的暂停功能:
//暂停判断,程序一进来就做判断;
if (_tickets == 90) 【给暂停条件】
{
//暂停
[_condition wait];
}
【什么时候解除暂停】
[self performSelector:@selector(until) withObject:nil afterDelay:3];
-(void)until
{
//唤醒线程
[_condition signal];
}
3.子线程给主线程传值的两种方法: 【系统自带的方法】
//************ 给主线程传数据 ****************,
//方法一
//第一个参数:选择器
//第二个参数:传参
//第三个参数:等待是否执行完毕
NSLog(@"000000000000000000000");
[self performSelectorOnMainThread:@selector(log:) withObject:@"1111111" waitUntilDone:YES];
NSLog(@"2222222222222222222222");
//方法二
[self performSelector:@selector(log:) onThread:[NSThread mainThread] withObject:@"444444" waitUntilDone:NO];
二、operation
1)创建operation的两种方法
//************ 创建operation的两种方式 **************
//第一个参数:表示调起线程的对象
//第二个参数:选择器
//第三个参数:传入的参数
//第一种方法
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(log) object:nil];
[operation start]; 【创建operation对象,开启对象】
//第二种方法
【这种方法创建的operation对象可以另外给线程添加任务】
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2222222222");
}];
[operation1 addExecutionBlock:^{ 【另外添加任务的方法】
//线程添加任务
NSLog(@"3333333");
}];
[operation1 start];
2)将operation对象添加到队列中
NSOperationQueue *q = [[NSOperationQueue alloc] init]; 【创建队列】
//先给依赖关系,即先排好顺序;
[operation1 addDependency:operation]; 【先排序】
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
//在添加到队列中;
[q addOperation:operation];
[q addOperation:operation1]; 【添加operation】
[q addOperation:operation2];
[q addOperation:operation3];
//最大并行数 如果设置为1 表示串行
[q setMaxConcurrentOperationCount:1];
3)用多线程申请数据
-(void)loadData
{
_imageArry = [NSMutableArray array];
NSMutableArray *qArr = [NSMutableArray array];
for (int i=0; i<_imgArr.count; i++) {
NSBlockOperation *operation = [NSBlockOperation 【创建多个线程】blockOperationWithBlock:^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:_imgArr[i]]]];
[_imageArry addObject:image];
if (i==_imgArr.count-1) {
【利用子线程传值的方法回到主线程刷新数据】
[_tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
//下面这个回到主线程的方法是在reloadData刷新数据借宿后调用的
dispatch_async(dispatch_get_main_queue(), ^{
【数据刷新成功以后调用这个方法,检测什么时候刷新结束】
NSLog(@"刷新结束");
});
}
}];
if (i>0) {
【给子线程添加依赖关系,即给子线程排序】
[operation addDependency:(NSOperation *)[qArr lastObject]];
}
[qArr addObject:operation];
}
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i= (int)qArr.count-1; i>=0; i--) {
[q addOperation:qArr[i]]; 【将子线程添加到队列中】
}
[q setMaxConcurrentOperationCount:1];
}
三、GCD
3 GCD
1.什么是GCD?
全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
纯C语言,提供了非常多强大的函数
2.GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
//1.延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// NSLog(@"11111");
});
//2.单例的创建
[self createManager];
-(void)createManager
{
//2.单例的创建
//创建一个执行一次的静态的线程
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//执行线程
manager = [[UIViewController alloc] init];
});
NSLog(@"----------%p",manager);
}
//3.进入异步 自动进入ios队列等待执行.开辟线程做某件事
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
//回到主线程做某件事
dispatch_async(dispatch_get_main_queue(), ^{
});
//4.先在异步做某件事情,然后回到主线程再做其他事情;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//回到主线程做某件事
dispatch_async(dispatch_get_main_queue(), ^{
});
});
//5.自定义线程,创建一个线程;
dispatch_queue_t urlq = dispatch_queue_create("1111", NULL);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, urlq, ^{
NSLog(@"222222");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"333333");
});
dispatch_group_notify(group, urlq, ^{
NSLog(@"000099999");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"4444444");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"5555555");
});
//下面这个代码块永远在一个组中最后一个执行
dispatch_group_notify(group, urlq, ^{
NSLog(@"000066666");
});