CPU在单位时间片里快速在各线程之间的切换安全
优势:bash
缺点:多线程
new
新建一个线程start
开始一个线程,线程进入就绪(runnable
)状态Running
)状态Running
状态以后会出现几种现象sleep
或等待同步锁,从可调度线程池中移除,进入阻塞(Blocked
)状态sleep
到时,获取到同步锁,从新添加回可调度线程池,再次进入就绪(Runnable
)状态注意:start
操做不可重复,当CPU调度当前线程,进入Running
状态时,这里存在一个可调度线程池,会进行一系列的判断,若是线程池里有当前线程,会直接执行线程,若是没有,则判断当前线程池的大小是否小于核心线程池的大小,若是小于,则建立一个新的线程来执行;若是大于,则等待被加入到队列等,具体能够参考下面的线程池工做原理。并发
具体代码看下线程的生命周期:oop
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 根据状态来改变 - 线程
if (self.t == nil) {
// new 新建
self.t = [[NSThread alloc] initWithTarget:self.p selector:@selector(testThreadStatus) object:@100];
// 2. 启动线程start - runnable
[self.t start];
self.t.name = @"学习线程";
}
}
- (void)testThreadStatus {
// running
for (int i = 0; i<10; i++) {
// blocked
if (i == 2) {
sleep(1);
}
}
[self.t cancel];
}
复制代码
流程图: 性能
在线程的生命周期中,须要考虑到当前的可调度线程池。 首先须要判断当前线程池的大小是否小于核心线程池大小,若是是小于,则直接建立线程去执行任务;若是是大于,则没有能力开辟新的线程去执行任务,只能依赖现有的线程,则须要判断工做队列是否已经满了,若是没有满,则将任务push到队列,执行任务;若是满了,判断线程池里的线程是否都工做,若是没有,则利用线程去执行任务;若是都在工做,则进入饱和策略。学习
饱和策略:ui
RejectedExecutionException
,该异常可由调用者捕获保证线程的安全,提升性能,具体可参考iOS的锁spa
runloop
与线程是一一对应的,一个runloop
对应一个核心的线程,为何说是核心的,是由于runloop
是能够嵌套的,可是核心的只能有一个,他们的关系保存在一个全局的字典里runloop
是来管理线程的,当线程的runloop
被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务runloop
在第一次获取时被建立,在线程结束时被销毁runloop
在程序一启动就默认建立好了runloop
是懒加载的,只有当咱们使用的时候才会建立,因此在子线程用定时器要注意:确保子线程的runloop
被建立,否则定时器不会回调