線程與進(jìn)程
線程是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程所有任務(wù)都在線程中執(zhí)行
進(jìn)程想要執(zhí)行任務(wù),必須得有線程,進(jìn)程至少要有一條線程
程序啟動(dòng)會(huì)默認(rèn)開啟一條線程,這條線程被稱為主線程或UI線程
進(jìn)程實(shí)質(zhì)在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序
每個(gè)進(jìn)程之前是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用的且受保護(hù)的內(nèi)存空間內(nèi)
通過(guò)“活動(dòng)監(jiān)視器”可以查看Mac系統(tǒng)中所開啟的進(jìn)程
進(jìn)程與線程的關(guān)系
地址空間:同一進(jìn)程的線程共享本進(jìn)程的地址空間,而進(jìn)程之間則是獨(dú)立的地址空間
資源擁有:同一進(jìn)程內(nèi)的線程共享本進(jìn)程的資源如內(nèi)存、I/O、cpu等,但是進(jìn)程之前的資源是獨(dú)立的。
- 一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響,但是一個(gè)線程崩潰整個(gè)進(jìn)程都死掉。所以多進(jìn)程要比多線程健壯。
- 進(jìn)程切換時(shí),消耗的資源大,效率高。所以涉及到頻繁的切換時(shí),使用線程要好于進(jìn)程。同樣如果要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程不能用進(jìn)程。
- 執(zhí)行過(guò)程:每個(gè)獨(dú)立的進(jìn)程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序入口。但是線程不能獨(dú)立執(zhí)行,必須已存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
- 線程是處理器調(diào)度的基本單位,但進(jìn)程不是。
- 線程沒有地址空間,線程包含在進(jìn)程地址空間中。
時(shí)間片的概念:CPU在多個(gè)任務(wù)直接進(jìn)行快速的切換,這個(gè)時(shí)間間隔就是時(shí)間片
- 單核CPU同一時(shí)間,只能處理一個(gè)線程
- 多線程同時(shí)執(zhí)行其實(shí)是CPU快速的在多個(gè)線程之前切換,CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程的“同時(shí)”執(zhí)行的效果
- 如果線程數(shù)非常多,CPU會(huì)在n個(gè)線程之間切換,消耗大量的CPU資源,導(dǎo)致每個(gè)線程唄調(diào)度的次數(shù)會(huì)降低,線程的執(zhí)行效率降低


飽和策略:
- AbortPolicy 直接拋出RejectedExecutionExeception異常來(lái)阻止系統(tǒng)正常運(yùn)行
- CallerRunsPolicy 將任務(wù)退回到調(diào)度者
- DisOldestPolicy 丟掉等待最久的任務(wù)
- DisCardPolicy 直接丟棄任務(wù)
這四種拒絕策略均實(shí)現(xiàn)在RejectedExecutionHandler接口
任務(wù)執(zhí)行速度的影響因素
- cpu狀態(tài)
- 任務(wù)復(fù)雜度
- 優(yōu)先級(jí)
- 線程狀態(tài)
優(yōu)先級(jí)反轉(zhuǎn):
- IO 密集型,頻繁等待
- CPU 密集型,很少等待
IO比CPU更容易得到優(yōu)先級(jí)提升
優(yōu)先級(jí)影響因素:
- 用戶指定
- 等待的頻繁度,頻繁調(diào)用優(yōu)先級(jí)會(huì)降低
- 長(zhǎng)時(shí)間不執(zhí)行,會(huì)提升優(yōu)先級(jí)
互斥鎖 發(fā)現(xiàn)其他線程執(zhí)行 當(dāng)前線程 休眠 (就緒狀態(tài)) 一直在等打開 喚醒執(zhí)行
自旋鎖 發(fā)現(xiàn)其他線程執(zhí)行 當(dāng)前線程 詢問(wèn) - 忙等 耗費(fèi)性能比較高
在短小精悍的項(xiàng)目里用自旋鎖,或者環(huán)境資源充足,比如mac環(huán)境,用自旋鎖
atomic 是原子屬性,是為多線程開發(fā)準(zhǔn)備的,是默認(rèn)屬性!
僅僅在屬性的 setter 方法中,增加了鎖(自旋鎖),能夠保證同一時(shí)間,只有一條線程對(duì)屬性進(jìn)行寫操作
同一時(shí)間 單(線程)寫多(線程)讀的線程處理技術(shù)
nonatomic 是非原子屬性
沒有鎖!性能高!
在源碼中可以看到
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
下面看個(gè)面試題:
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");
輸出結(jié)果順序是:1 5 2 3 4

再看下面一段代碼:
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");
輸出結(jié)果是: 1 5 2 崩潰

這個(gè)會(huì)造成死鎖。第二個(gè)塊會(huì)往第一個(gè)塊后面增加一個(gè)任務(wù),第二個(gè)塊任務(wù)不執(zhí)行完,是執(zhí)行不了第一個(gè)塊下面的代碼,但是第一個(gè)塊代碼不執(zhí)行完,又不能執(zhí)行第二個(gè)塊里面的代碼,相互等待造成死鎖。
再看一種情況:
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");
輸出結(jié)果是: 1 5 2 4 3
