线程与进程
-
线程是进程的基本执行单元,一个进程所有任务都在线程中执行
-
进程想要执行任务,必须得有线程,进程至少要有一条线程
-
程序启动会默认开启一条线程,这条线程被称为主线程或UI线程
-
进程实质在系统中正在运行的一个应用程序
-
每个进程之前是独立的,每个进程均运行在其专用的且受保护的内存空间内
-
通过“活动监视器”可以查看Mac系统中所开启的进程
进程与线程的关系
地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之前的资源是独立的。
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
- 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
- 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须已存在应用程序中,由应用程序提供多个线程执行控制。
- 线程是处理器调度的基本单位,但进程不是。
- 线程没有地址空间,线程包含在进程地址空间中。
时间片的概念:CPU在多个任务直接进行快速的切换,这个时间间隔就是时间片
- 单核CPU同一时间,只能处理一个线程
- 多线程同时执行其实是CPU快速的在多个线程之前切换,CPU调度线程的时间足够快,就造成了多线程的“同时”执行的效果
- 如果线程数非常多,CPU会在n个线程之间切换,消耗大量的CPU资源,导致每个线程呗调度的次数会降低,线程的执行效率降低
饱和策略:
- AbortPolicy 直接抛出RejectedExecutionExeception异常来阻止系统正常运行
- CallerRunsPolicy 将任务退回到调度者
- DisOldestPolicy 丢掉等待最久的任务
- DisCardPolicy 直接丢弃任务
这四种拒绝策略均实现在RejectedExecutionHandler接口
任务执行速度的影响因素
- cpu状态
- 任务复杂度
- 优先级
- 线程状态
优先级反转:
- IO 密集型,频繁等待
- CPU 密集型,很少等待
IO比CPU更容易得到优先级提升
优先级影响因素:
- 用户指定
- 等待的频繁度,频繁调用优先级会降低
- 长时间不执行,会提升优先级
互斥锁 发现其他线程执行 当前线程 休眠 (就绪状态) 一直在等打开 唤醒执行
自旋锁 发现其他线程执行 当前线程 询问 - 忙等 耗费性能比较高
在短小精悍的项目里用自旋锁,或者环境资源充足,比如mac环境,用自旋锁
atomic
是原子属性,是为多线程开发准备的,是默认属性!
仅仅在属性的 setter
方法中,增加了锁(自旋锁),能够保证同一时间,只有一条线程对属性进行写操作
同一时间 单(线程)写多(线程)读的线程处理技术
nonatomic
是非原子属性
没有锁!性能高!
在源码中可以看到
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
下面看个面试题:
dispatch_queue_t queue = dispatch_queue_create("sj", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
输出结果顺序是:1 5 2 3 4
image再看下面一段代码:
dispatch_queue_t queue = dispatch_queue_create("sj", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
输出结果是: 1 5 2 崩溃
image这个会造成死锁。第二个块会往第一个块后面增加一个任务,第二个块任务不执行完,是执行不了第一个块下面的代码,但是第一个块代码不执行完,又不能执行第二个块里面的代码,相互等待造成死锁。
再看一种情况:
dispatch_queue_t queue = dispatch_queue_create("sj", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_async(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
输出结果是: 1 5 2 4 3
image
网友评论