程序
由源代码生成的可执行应用
进程
正在运行的一个应用程序,就是一个进程。每一进程都至少有一条线程,叫主线程。进程拥有独立运行所需的全部资源。
一个进程是由一个或多个线程组成。进程只负责资源的调度和分配。线程才是程序真正的执行单元,负责代码的执行。
线程
每一个线程都是独立的,可以执行任务。除了主线程以外的 都叫子线程 子线程可以有很多个,但是线程是耗费资源的(一般最多不超过5条 注:3条最佳)。 程序退出后,会清空线程的任务。
主线程操作什么样的任务?
UI界面、按钮点击、屏幕的滚动(一切用户看得到的,都要在主线程当中去操作)。比较大的耗时操作,又或者用户看不见的操作,可以放在子线程当中去做,比如,下载、解压缩、读取大型数据等 可以在子线程中操作。多线程的原理
CPU在工作时 同一时间只能执行一个任务。之所以可以造成多条线程一起执行任务的假象,是CPU在进行高速的切换(调度),在线程之间切换,来达到多个任务一起执行的效果。多线程的优点
1.可以大大提高执行任务的效率
2.可以让用户有更好的用户体验多线程的缺点
如果大量的开辟线程,会造成程序的卡顿,耗费过量的资源线程休眠
[NSThread sleepForTimeInterval:5];
判断当前线程是否是主线程
[NSThread isMainThread]
当前线程
[NSThread currentThread]
开辟子线程
performSelectorInBackground
[self performSelectorInBackground:@selector(xxxx:) withObject:@"123"];
方法是基类提供的,只要是对象,都能调用。
初始化开辟子线程
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(xxxx:) object:@"222"]; [thread start];
detachNewThreadSelector
[NSThread detachNewThreadSelector:@selector(xxxx:) toTarget:self withObject:@"111"];
这个方法不用开始,自动执行线程中的任务。
回到主线程
performSelectorOnMainThread
[self performSelectorOnMainThread:@selector(xxxxxx:) withObject:image waitUntilDone:NO];
waitUntilDone : 是否等待回到主线程的方法执行完毕后再向下执行
获取主线程
[self performSelector:@selector(xxxxxx:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
多线程
常用的开启多线程方法
1.NSOperation 封装GCD的方法 提供OC的语法来使用GCD
2.GCD 是苹果推荐的 可以最大化的发挥多核CPU 是C语言的函数使用GCD或者NSOperation,往合适的队列中添加任务 其他的 系统会根据队列的类型开启线程去完成任务。
优势:不用程序员管理线程的生命周期线程队列
(任务中心,可以执行很多任务)
1.串行队列 主线程相当于一个串行队列 队列中的任务需要一个执行完毕后再执行下一个
2.并行队列 队列中得任务进行并发执行 同时开始未必同时结束同步:没有开启子线程的能力
异步:拥有开启子线程的能力线程之间的通信
在子线程中 完成耗时的操作,完成后需要回到主线程进行UI刷新。
主线程和子线程是独立的
NSOperation
NSOperation 是一个抽象类,使用子类NSInvocationOperation或NSBlockOperation来执行。
使用方法
创建一个队列,开启一个线程,把任务添加到队列中。需要把NSInvocationOperation对象放进一个队列里,才能开启子线程。
// 创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
// 给队列提供一个可以设置最大并发数
// 一次最多并发执行2个任务
queue.maxConcurrentOperationCount = 2;
// 开启一个线程 (相当于 一个任务)
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad:) object:@"123"];
// 把任务添加到队列中
// 只需要把任务添加进队列中,不需要操作会自动执行
// 不是添加一个任务 就开启一个线程
// 这个操作是系统做的 有的线程会被系统重复利用(优化)
[queue addOperation:operation];
// 往队列中添加任务
[queue addOperationWithBlock:^{
// block中就是你要添加的任务
NSLog(@"%@",[NSThread currentThread]);
}];
// 初始化任务
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
// 添加的任务
NSLog(@"--- 4 --- %@", [NSThread currentThread]);
}];
// 添加进队列中
[queue addOperation:blockOperation];
GCD
以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。GCD属于函数级的多线程,性能更高,功能更加强大。任务:具有一定功能的代码段。一般是一个block或者函数
队列
1.并行队列 系统提供的一个全局的并行队列(整个应用都可以使用) 如果不想用也可以创建一个出来
2.串行队列 需要创建一个出来任务
1.同步 不具备开启线程的能力
2.异步 具有开启线程的能力分四种情况
1.并行 —- 异步任务
2.并行 —- 同步任务
3.串行 —- 异步任务
4.串行 —- 同步任务
并行 —- 异步任务 (重要)
// 开启子线程 并且任务并发
- (void)asyncGlobleQueue
{
// 获取全局的并发队列
// dispatch_queue_t 队列的类型
// 参数1 是CPU切换的频率高度(切换的优先级)
// 参数2 是个预留参数 可以填0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 添加异步任务
// 参数1 给哪个队列添加任务
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
});
}
并行 —- 同步任务
// 没有开启子线程 相当于变成了一个串行的队列
- (void)syncGlobleQueue
{
// 创建一个并行队列
// 参数1 队列的标示符 反向域名 com.lanou3g.www
// 参数2 填要创建的队列的类型(串/并)
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.www", DISPATCH_QUEUE_CONCURRENT);
// 添加同步任务
dispatch_sync(queue, ^{
NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
});
// 创建的队列是需要释放的(ARC 不用释放)
dispatch_release(queue);
}
串行 —- 异步任务
// 开启子线程 串行
- (void)asyncSericlQueue
{
// 创建串行队列
dispatch_queue_t queue = dispatch_queue_create("haha", DISPATCH_QUEUE_SERIAL);
// 添加异步任务
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
// 添加任务的
NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
});
dispatch_release(queue);
}
串行 —- 同步任务
// 没有开启线程 都在主线程 顺序执行
- (void)syncSericlQueue
{
dispatch_queue_t queue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);
// 添加同步任务
dispatch_sync(queue, ^{
NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
});
dispatch_release(queue);
}
多个线程对一个数据进行操作
解决方案: 访问数据,加一个锁,只能有1个线程访问。等这个线程访问结束后才能让下一个线程再访问,保证数据被访问的安全。
// 添加同步锁 (互斥锁)
self.lock = [[NSLock alloc]init];
[lock lock]; // 上锁
// 中间就是被上锁的部分
[lock unlock]; // 解锁
GCD开启线程 (重要)
GCD开启线程加载图片 回到主线程刷新UI
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 做请求 耗时操作 (同步请求)
// 在子线程中 同步请求就相当于异步请求
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic24.nipic.com/20121022/9252150_193011306000_2.jpg"]];
UIImage *image = [UIImage imageWithData:data];
// 回到主线程 刷新界面
// 取出主线程 dispatch_get_main_queue()
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程要执行的任务
// 刷新UI
});
});