目录
1. 概念
2. 使用(4种方式)
1.概念 (程序、进程、线程、多线程)
程序
一个应用就是一个程序,用于完成某种功能。
启动一个应用程序后,会创建一个进程,该进程会创建一个主线程。
进程
1、简介
(1)一个进程是指在系统中正在运行的一个应用程序。
(2)进程间相互独立,每个进程均运行在其专用且受保护的内容空间内。
(3)通过“活动监视器”可以查看mac系统中所开启的进程。
2、进程通信
单机系统中进程通信有四种形式:主从式、会话式、消息或邮箱机制、共享存储区方式。
主从式例子:终端控制进程和终端进程。
会话式例子:用户进程与磁盘管理进程之间的通信。
线程
简介
(1)线程(Thread),也称作轻量级进程。线程是进程的组成部分,一个进程可以拥有多个线程(至少有一个主线程)。
(2)线程在程序中是独立的、并发的执行流,当进程被初始化后,主线程就被创建了。
(3)可以在进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程是相互独立的。
(4)线程是独立运行的,单个线程他是不知道进程中是否存在其他的线程,线程的执行是抢占式的。(当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行)。
(5)3个基本状态:就绪,执行,阻塞
(6)一个进程要想执行任务,必须得有线程(每一个进程至少要有一条线程,可以有多个线程)。
(7)线程是进程的基本执行的单元,一个进程(程序)的所有的任务都在线程中执行。
(8)一个线程中的任务的执行是串行的。(如果要在一个线程中执行多个任务,那么只能一个一个地按照顺序执行这些任务)。
(9)在同一时间内,一个线程只能执行一个任务。
线程的生命周期是:新建 - 就绪 - 运行 - 阻塞 - 死亡
多线程
1、简介
(1)一个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务。
(2)多线程技术可以提高程序的执行效率。
2、原理(单核)
(1)同一时间,CPU只能处理一条线程,只有一条线程在工作(执行)。
(2)多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)。
(3)如果CPU调度线程的时间足够快,就会造成了多个线程并发执行的假象。
(4)如果线程非常多,CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源,每条线程被调用执行的频次会降低(线程的执行效率降低)。
3、优缺点
优点:
适当提高程序的执行效率、资源利用率(CPU、内存利用率)。
(1)对于单线程的应用而言,整个应用只有一个顺序执行流,当执行流在某个耗时操作或不能立即完成的任务时(如网络请求、复杂的操作和运行过程、某些必须消耗一定时间后才能完成的操作),该执行流就会被阻塞,整个应用就会被卡在那里无法继续执行,因此单线程的程序往往功能非常有限。
(2)在实际应用中多线程是非常有用的,例如:用户操作界面上的某个按钮时,该按钮需要执行的任务需要几秒甚至十几秒,如果直接在UI线程(主线程)中完成这个任务,在该任务执行完成、返回之间,UI线程被该任务阻塞,无法响应用户的其他操作(这段时间内,用户对iOS系统的操作将不会有任何反应,除非用户单机Home键返回,但这并不是用户希望的结果)。
缺点:
(1)开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。
(2)线程越多,CPU在调度线程上的开销就越大。
(3)程序设计更加复杂:如线程之间的通信,多线程的数据共享。
4、在iOS开发中的应用
一个iOS程序运行后,默认会开启1条线程,称为主线程(UI线程)。
主线程用来
1、显示、刷新UI界面
2、处理UI事件(点击事件、滚动事件、拖曳事件等)。
比较耗时的操作不要放在主线程中。耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种卡的坏的体验。
多线程资源共享带来的安全隐患
一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源。当多个线程访问同一资源时,很容易引发数据散乱和数据安全问题。(如多个线程访问同一个对象、同一个变量、同一个文件)。
解决方法:使用互斥锁
使用的格式:@synchronized(锁对象){//需要锁定的代码} 注:锁定一份代码只用一把锁,用多吧锁是无效的。
互斥锁的优点
能有效防止因多线程抢夺资源造成的数据安全问题
互斥锁的缺点
需要消耗大量的CPU资源。
互斥锁的使用前提
多条线程抢夺同一块资源。(互斥锁就是使用了线程同步技术,多条线程按顺序地执行任务)。
示例:在创建单例模式时,最好使用互斥锁。
static UserInfo *singletonUserInfo = nil;
+(UserInfo *)shareUserInfo{
@synchronized(self){
//创建一个线程锁,防止多线程中多次创建
if (singletonUserInfo == nil) {
singletonUserInfo = [[UserInfo alloc]init];
NSLog(@"初始化");
}
}
return singletonUserInfo;
}
atomic
原子性,为setter方法加锁(默认就是atomic),线程安全,需要消耗大量的资源
nonatomic
非原子性,不会为setter方法加锁,非线程安全,适合内存小的移动设备
iOS开发:最好所有属性都声明为nonatomic,尽量避免多线程抢夺同一块资源,尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。
简单总结
1.一个程序至少有一个进程,一个进程至少有一个线程。
进程创建则主线程创建,主线程死掉则进程死掉。
2.进程是最小的资源分配单位,线程是最小的CPU执行单位。
进程之间相互独立,且所有任务都交由线程去执行。
多个线程之间相互独立,但共享同一进程的资源。
3.更新UI要放在主线程中(否则:防止造成卡顿,避免多个子线程同时操作UI)
同步/异步/串行/并行
同步:任务块完成后再继续向下执行
异步:跳过任务块继续向下执行
串行:是指一个队列,队列中的任务依次执行
并行:是指一个队列,队列中的任务同时执行
4种(首先先考虑队列,再考虑同异步)
同步串行(在串行队列中,造成死锁)
同步并行
异步串行
异步并行
2. 使用(4种方式)
- pthread
基于C语言
#import <pthread.h>
// 1. 创建线程
pthread_t thread;
// 2. 开启线程(线程,线程属性,函数,函数参数)
pthread_create(&thread, NULL, run, NULL);
// 3. 设置该线程运行结束后自动释放所有资源
pthread_detach(thread);
// 线程操作方法(放在OC方法外)
void *run(void *param){
for(int i=0;i<1000;i++){
NSLog(@"%d=====%@",i, [NSThread currentThread]);
}
return NULL;
}
pthread_cancel(thread); // 中断指定线程
pthread_exit(thread); // 终止指定线程
// 待改
pthread_join() 阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init() 初始化线程的属性
pthread_attr_setdetachstate() 设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate() 获取脱离状态的属性
pthread_attr_destroy() 删除线程的属性
pthread_kill() 向线程发送一个信号
- NSThread
创建线程
(方式一)(创建后调用start启动)
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(method:) object:@""];
(方式二)(创建后调用start启动)
NSThread *thread1=[[NSThread alloc]initWithBlock:^{
}];
(方式三)(创建后自动启动)
[NSThread detachNewThreadSelector:@selector(method:) toTarget:self withObject:@""];
(方式四)(创建后自动启动)
[NSThread detachNewThreadWithBlock:^{
}];
(方式五)(隐式创建)
//
[self performSelector:@selector(method)];
[self performSelector:@selector(method) withObject:nil];
[self performSelector:@selector(method) withObject:nil withObject:nil];
[self performSelector:@selector(method) withObject:nil afterDelay:1.0];
[self performSelector:@selector(method) withObject:nil afterDelay:1.0 inModes:@[NSRunLoopCommonModes]];
//
[self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true];
[self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
//
[self performSelectorInBackground:@selector(method) withObject:nil];
// 主线程
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
thread实例方法
// 是否是主线程
BOOL isMain=[thread isMainThread];
// 是否正在执行
BOOL isExecuting=[thread isExecuting];
// 是否已结束
BOOL isFinished=[thread isFinished];
// 是否被取消
BOOL isCanceled=[thread isCancelled];
// 获取线程名
NSString *threadName=thread.name;
// 设置线程名
[thread setName:@"name"];
// start
[thread start];
// cancel
[thread cancel];
// 获取所占的栈区大小
NSUInteger *size=[thread stackSize];
// 设置所占的栈区大小
[thread setStackSize:1024*5];
// 获取优先级
double x=thread.threadPriority;
// 设置优先级
[thread setThreadPriority:1000];
NSThread类方法
// 获取主线程
NSThread *mainThread=[NSThread mainThread];
当前线程相关
// 获取当前线程
NSThread *currentThread=[NSThread currentThread];
// 杀死当前线程
[NSThread exit];
// 阻塞当前线程10s
[NSThread sleepForTimeInterval:10];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
// 判断当前线程是否多线程
BOOL isMutiThread=[NSThread isMultiThreaded];
// 判断当前线程是否是主线程
BOOL isMainThread=[NSThread isMainThread];
// 获取/设置当前线程的调度优先级
// 调度优先级的取值范围是0.0~1.0,默认0.5,值越大,优先级越高。
double priority=[NSThread threadPriority];
// 设置调度优先级
[NSThread setThreadPriority:0.5];
通知
// 即将进入多线程模式
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willBecomeMuti:) name:NSWillBecomeMultiThreadedNotification object:nil];
// 进入单线程模式
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(becomeSigle:) name:NSDidBecomeSingleThreadedNotification object:nil];
// 线程退出
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willExit:) name:NSThreadWillExitNotification object:nil];
- GCD
自动管理线程的生命周期(创建线程,调度任务,销毁线程等)
同步/异步
主线程队列/全局线程队列/自定义线程队列
// 同步 1.主线程队列(串行)
dispatch_sync(dispatch_get_main_queue(), ^{
});
// 异步 2.全局线程队列(并行)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 耗时操作
// 。。。
dispatch_async(dispatch_get_main_queue(), ^{
// UI操作
// 。。。
});
});
3.自定义线程队列
// 串行
dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
// 并行
dispatch_queue_t queue2=dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
延迟
// 延迟2s执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*2), dispatch_get_main_queue(), ^{
});
重复
// 重复3次执行
dispatch_apply(3, dispatch_get_main_queue(), ^(size_t x) {
});
onlyOne
// 仅执行一次
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
//
});
栅栏(任务先后)
// dispatch_barrier_async先执行栅栏之前任务,再执行栅栏任务,再执行栅栏后的任务
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-1");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-2");
});
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@"dispatch-barrier");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-3");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-4");
});
组 (任务先后) dispatch_group_t
//
dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group=dispatch_group_create();
dispatch_group_async(group, dispatchQueue, ^{
});
dispatch_group_async(group, dispatchQueue, ^{
});
// group内所有队列完成后调用
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});
// 设置最大并行数
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 创建信号量,并且设置值为3
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++){
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSLog(@"%i",i);
sleep(2);
// 每次发送信号则semaphore会+1,
dispatch_semaphore_signal(semaphore);
});
}
/*
同步锁
// dispatch_semaphore_t 信号量:用于同步
// 1.创建信号量(个数>=0) (放在代码块上)
dispatch_semaphore_t semaphore=dispatch_semaphore_create(0);
// 2.信号量个数+1 (放在代码块中)
dispatch_semaphore_signal(semaphore);
// 3. 等待直到信号量个数>0 (放在代码块下)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 3. 10s内等待直到信号量个数>0
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10));
*/
同步锁2
dispatch_group_t group=dispatch_group_create();
// 进入组
dispatch_group_enter(group);
dispatch_group_async(group, dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT), ^{
// 离开组
dispatch_group_leave(group);
});
/*
成对
// 进入组
dispatch_group_enter(group);
dispatch_group_async(group, dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT), ^{
// 离开组
dispatch_group_leave(group);
});
*/
// 等待直到离开组
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- NSOperation
NSOperation是对GCD的封装。
相比GCD
优点:比GCD更强大(能处理大量的并发请求,更好的处理队列之间的依赖关系)
缺点:比GCD效率低.
自动管理线程的生命周期(创建线程,调度任务,销毁线程等)
// 1.创建queue队列
NSOperationQueue *optionQueue=[NSOperationQueue new];
// 主队列(串行,最大并行数:1)
// NSOperationQueue *que=[NSOperationQueue mainQueue];
// 1.1设置queue最大并行数(为1则串行,默认:-1并行)
[optionQueue setMaxConcurrentOperationCount:5];
// 将option加入queue,会自动执行,不用option start
// 2.添加blockOption到queue
// : NSOperation
// 创建option
NSBlockOperation *option=[NSBlockOperation blockOperationWithBlock:^{
}];
// 设置option代码块完成时调用
[option setCompletionBlock:^{
}];
// 添加option到queue
[optionQueue addOperation:option];
// 2.1 option添加依赖(option2完成后才能执行option1)
NSBlockOperation *option2=[NSBlockOperation blockOperationWithBlock:^{
}];
[option addDependency:option2];
// 删除依赖
[option removeDependency:option2];
// 2.2 添加
[option addExecutionBlock:^{
}];
// 2.添加匿名blockOption到queue
[optionQueue addOperationWithBlock:^{
}];
// 2. 添加InvocationOperation到queue
// : NSOperation
NSInvocationOperation *option=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(method) object:nil];
// 添加option到queue
[optionQueue addOperation:option];
// 2. 添加option数组
[optionQueue addOperations:@[] waitUntilFinished:true];
queue 队列方法
// queue是否暂停
BOOL isSuspended=[optionQueue isSuspended];
// queue暂停
[optionQueue setSuspended:true];
// queue取消所有option
[optionQueue cancelAllOperations];
// 阻塞直到queue所有option完成
[optionQueue waitUntilAllOperationsAreFinished];
// 设置/获取 name
[optionQueue setName:@""];
NSString *name=optionQueue.name;
// 获取 option数量(readOnly)
NSUInteger operationCount=optionQueue.operationCount;
// 获取 最大option数量
NSInteger maxConcurrentOperationCount=optionQueue.maxConcurrentOperationCount;
option(NSOperation) 方法
// option设置name
[option setName:@""];
// option 开始
[option start];
// option 取消
[option cancel];
// 阻塞直到执行完毕
[option waitUntilFinished];
// 获取优先级
NSOperationQueuePriority queuePriority=option.queuePriority;
// 设置优先级
[option setQueuePriority:NSOperationQueuePriorityHigh];
/*
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
*/
// option 是否取消
BOOL isCanceled=[option isCancelled];
// option 是否正在执行
BOOL isExecuting=[option isExecuting];
// option 是否结束
BOOL isFinished=[option isFinished];
// option 是否异步
BOOL isAsy=[option isAsynchronous];
// 是否就绪
BOOL isReady=[option isReady];
// 获取依赖列表
NSArray<NSOperation *> *dependencies=option.dependencies;
自定义NSOperation
#import <Foundation/Foundation.h>
@protocol YTOperationCompletionDelegate
// 更新UI
-(void)opCompletion:(NSString *)str; // 参数看实际情况变化
@end
@interface YTMyOperation : NSOperation
@property (nonatomic,weak) id<YTOperationCompletionDelegate> dele;
@end
#import "YTMyOperation.h"
@implementation YTMyOperation
-(void)main{
//
[super main];
// 一些操作
//...
//
dispatch_async(dispatch_get_main_queue(), ^{
if(self.dele){
[self.dele opCompletion:@"complete"];
}
});
}
@end
网友评论