线程与进程的关系:
1>进程和应用程序的关系:进程为应用程序开辟内存空间
2>程和应用程序的关系:线程执行应用程序中的代码
3>进程和线程的关系:进程是由线程组成的,一个进程至少包含一条线程(主线程)
runloop和线程有什么关系?
1.每一个线程中都⼀个runloop,只有主线的的runloop默认是开启的,其他线程的runloop是默认没有开启的
2.可以通过CFRunLoopRun()函数来开启⼀一个事件循环
3.看SDWebImage源码的时候⻅到有这么⽤过.
runloop的model作用是什么?
model主要是用来指定时间在运行循环中的优先级的 苹果公开提供的Mode有两个:
kCFRunLoopDefaultMode
kCFRunLoopCommonModes
如果我们把一个NSTimer对象以kCFRunLoopDefaultMode添加到主运行循环中的时候,当一直 有用户事件处理的时候,NSTimer将不再被调度 如果我们把一个NSTimer对象以kCFRunLoopCommonModes添加到主运行循环中的时候,当一 直有用户事件处理的时候,NSTimer还能正常的调度,互不影响.
runloop内部的实现:
1.他是一个死循环
2.如果事件队列中存放在事件,那就取出事件,执⾏行相关代码
3.如果没有事件,就挂起,等有事件了,⽴立即唤醒事件循环,开始执⾏
在多线程的中使用block:
block在管理子线程以及线程的创建个销毁是由队列负责的,直接在block中使用self没有关系,不会造成循环引用
多线程:就是多条线程,也指并发编程
多线程的底层是通过Mach实现的
开发多线程的多种方案:
1>C语言POSIX接口:#include
2>OC的NSThread
3>C语言的CGD接口( 性能最好 , 代码最精简 )
4>OC的NSOperationn和NSOperationQueue (基于CGD)
线程间通信:
//最后一个参数:是否等待调用方法执行结束!
<1>[selfperformSelectorOnMainThread:@selector(setImageWithImage:) withObject:nilwaitUntilDone:YES];
<2>[selfperformSelector:@selector(setImageWithImage:) onThread:[NSThread mainThread] withObject:nilwaitUntilDone:YES];
3>经典组合:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
//在这里执行耗时操作
dispatch_async(dispatch_get_main_queue(), ^{
//在这里更新UI界面
});
});
一般通信会使用在子线程下载数据,做一些耗时操作,在主线程更新UI界面
使用NSThread开启线程的方式
//创建线程的几种方式
//1>直接创建一条子线程
NSThread*thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(run)object:nil];
//开启线程
[threadstart];
//获取主线程
[NSThreadmainThread];
//检测当前线程是否为主线程
NSLog(@"%d",[NSThreadisMainThread]);
//2获取当前线程
NSThread*currentThread = [NSThreadcurrentThread];
//判断当前线程的状态(线程所处的位置)
BOOLis = [currentThreadisMainThread];
//设置线程的名字
[currentThreadsetName:@"123"];
//3直接创建一条线程
[NSThreaddetachNewThreadSelector:@selector(run1)toTarget:selfwithObject:nil];
//4开启一条隐式线程
[selfperformSelectorInBackground:@selector(run1)withObject:nil];
线程的生命周期:
新建一个线程->开启->等待CPU调度->执行任务/强制退出/异常->线程结束/死亡
注意:一旦线程死亡之后,就不会被调度,也就是不会再执行该线程中任务
线程的阻塞:
1>在开启线程之后,如果执行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥锁,都会导致线程阻塞blocked
2>在CPU调度线程后,线程中的任务正在执行 ,如果执行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥锁,都会导致线程阻塞blocked
线程之间资源共享问题:
同一个资源被多条线程同时访问的时候会造成数据信息错误的问题 例子:在不同的地方同一时间去ATM取钱,一个在存.一个在取
问题解决方案:
添加互斥锁
@synchronized(锁对象) {//需要锁定的代码}
注意:锁定1份代码只用1把锁,用多把锁是无效的
互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
互斥锁的使用前提:多条线程抢夺同一块资源
相关专业术语:线程同步
线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务)
互斥锁,就是使用了线程同步技术
添加互斥锁的技巧 :[[NSUserDefaultsstandardUserDefaults]synchronize];利用此行代码可以敲出@synchronized
同步函数(sync)和异步函数 (async)与 线程之间的关系:
1>同步函数 + 串行队列 : 没有开启新线程,串行执行任务
2>同步函数 + 并行队列 : 没有开启新线程,串行执行任务
3>同步函数 + 主队列 : 没有开启新线程 ,卡住主线程
总结:同步函数执行任何类型队列,都不会开启新线程;都是在当前线程执行任务,同步函数不具备开启新线程的能力
1>异步函数 + 串行队列 : 会开启一条新的线程,并且任务按顺序执行
2>异步函数 + 并行队列 : 会开启多条子线程,任务同时执行
3>同步函数 + 主队列 : 没有开启新线程,任务按顺序执行
注意:使用sync函数往当前串行队列添加任务,会卡住当前的串行队列.
GCD的队列(dispatch_queue_t)分哪两种类型?
串⾏行队列和并⾏行队列
队列决定了操作是在主线程执行还是子线程执行
如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张 图片,然后在都下载完成后合成一张整图)
1.创建异步队列
2.创建dispatch_group_tdispatch_group_t =dispatch_group_create();3.通过组来执⾏行异步下载任务
dispatch_group_async(dispatch_group_t, dispatch_queue_t, ^{
NSLog(@"下载图片");
});
4.等到所有任务完成
dispatch_group_wait(dispatch_group_t,DISPATCH_TIME_FOREVER);
5.合成图⽚
dispatch_barrier_async的作用是什么?
barrier:是障碍物的意思,在多个并⾏行任务中间,他就像是⼀一个隔离带,把前后的并⾏行任务分开.dispatch_barrier_async作⽤用是在并⾏行队列中,等待前⾯面操作并⾏行任务完成 在执⾏行dispatch_barrier_async中的任务 如果后⾯面还有并⾏行任务,会开始执⾏行后续的并⾏行任务
苹果为什么要废弃dispatch_get_current_queue?
容易误⽤用造成死锁
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}只能输出1,然后线程主线程锁死
有4个术语比较容易混淆:同步、异步、并发、串行
同步和异步主要影响:能不能开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行主要影响:任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
>同步函数:同步就是顺序依次执行,如果在子线程上就是在子线程处理,但是不会建立新线程
>只在主线程上操作
dispatch_sync(dispatch_get_main_queue()^{
})
1.1在主线程操作会遵循PIPE的队列顺序去操作
1.2但是这样资源一旦多了起来就会导致主线程堵塞
>同步并发处理
>什么是并发
并发是在同一条线程内开启多个队列一起处理,就比如你玩游戏在玩MMORPG的时候你打怪物的同时怪物也在攻击你,这就是并发.
dispatch_sync(dispatch_get_glodal_queue(0,0), ^{
//括号(0,0)是干嘛的?
//它是用来对队列任务进行一个优先级处理
//现在这个东西可以忽略不计
//当然有三个级别
//2:是是最高级别0:正常级别-2:最低级别
});同步函数的特性就是不会建立新线程,所以不会创建新线程会依次处理完
在队列上得所有任务,执行完毕进行一个结果返回.
>同步串行处理
>什么是串行
串行会创建一条新线程.但是会依次对任务进行一个操作处理
dispatch_sync(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{
});
其实串行队列和同步函数的是相同的原理,所以同步串行其实没什么用,但是也会用得到,比如控制程序在手机上面的用电量,多开线程耗电会增加,如果有这个需求可以使用同步串行
>异步函数
异步函数就是会并发执行,执行完成一个返回一个是无序的,具有开启新线程的功能
>只在主线程操作
dispatch_async(dispatch_get_main_queue()^{
})在主线程都是依次操作
>异步并发处理
dispatch_async(dispatch_get_glodal_queue(0,0),^{
});
异步并发:
1.多个任务在多条线程下同时进行
2.没有排队,无序,这样容易导致出错
>异步串行处理
dispatch_async(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{
});
异步串行:
1.多个任务在多条线程下同时进行
2.有序排队,等每一条有执行完在进行下一个任务的操作
同步操作/异步操作总结:
1.无论是异步同步在主线程上都是依次执行
2.同步操作会依次进行操作,异步操作则是无序执行
3.同步操作不会开启新线程,异步操作会开启新线程
4.异步并发容易出错,无序不排队,会导致数据丢失
5.异步串行,安全有序
6.同步并发,限制线程开启,但是依次执行
7.同步串行,其实两个作用都是相同的,但是由于同步不具备开启线程,所以还是依次执行,特殊情况下课考虑使用
并发队列的开启:
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_tdispatch_get_global_queue(
dispatch_queue_priority_tpriority,//队列的优先级
unsignedlongflags);//此参数暂时无用,用0即可
dispatch_queue_tqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//获得全局队列
全局并发队列的优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH2//高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT0//默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)//低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN//后台
串行队列的创建:
GCD中获得串行有2种途径
使用dispatch_queue_create函数创建串行队列
dispatch_queue_t
dispatch_queue_create(constchar*label,//队列名称
dispatch_queue_attr_tattr);//队列属性,一般用NULL即可
dispatch_queue_tqueue =dispatch_queue_create("cn.itcast.queue",NULL);//创建
dispatch_release(queue);//非ARC需要释放手动创建的队列
使用主队列(跟主线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列
放在主队列中的任务,都会放到主线程中执行
使用dispatch_get_main_queue()获得主队列
dispatch_queue_tqueue =dispatch_get_main_queue();
延时执行:
iOS常见的延时执行有2种方式
1>调用NSObject的方法
[selfperformSelector:@selector(run)withObject:nilafterDelay:2.0];
// 2秒后再调用self的run方法
2>使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
// 2秒后执行这里的代码...在哪个线程执行,跟队列类型有关
});
GCD使用的在单例对象
//一次性代码,(单例的创建)
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
//在这里创建只需要所一个的对象和对象属性的配置信息
});
GCD中队列组的使用
//队列组的使用
dispatch_group_tgroup =dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//执行一个耗时操作
});
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//执行另外一个耗时操作
});
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
//回到主线程执行的操作
});
GCD中两个特殊的队列
//创建主队列
dispatch_queue_tmainQueue =dispatch_get_main_queue();
//创建全局并发队列
dispatch_queue_tglobalQueue =dispatch_get_global_queue(0,0);
GCD使用有两个步骤:
1>将任务添加到队列中;
2>选择同步还是异步的方式执行任务.