本節(jié)將介紹內(nèi)存五大區(qū)和多線程:
- 內(nèi)存五大區(qū)
- 多線程
- 互斥鎖與自旋鎖
- atomic與nonatomic的區(qū)別
- 線程與RunLoop
1. 內(nèi)存五大區(qū)
按照地址從高到低排列: 棧區(qū) -> 堆區(qū) -> 全局靜態(tài)區(qū) -> 常量區(qū) -> 代碼區(qū) (內(nèi)核區(qū)和保留部分不再考慮范圍內(nèi))

補(bǔ)充說(shuō)明:
內(nèi)存五大區(qū),實(shí)際是指虛擬內(nèi)存,而不是真實(shí)物理內(nèi)存。(詳情可查看?? 本文第3點(diǎn) 虛擬內(nèi)存與物理內(nèi)存)iOS系統(tǒng)中,應(yīng)用的虛擬內(nèi)存默認(rèn)分配4G大小,但五大區(qū)只占3G,還有1G是五大區(qū)之外的內(nèi)核區(qū)
1.1 棧區(qū)
- 函數(shù)內(nèi)部定義的
局部變量和數(shù)組,都存放在棧區(qū); (比如每個(gè)函數(shù)都有的(id self, SEL _cmd)) - 棧區(qū)的
內(nèi)存空間由系統(tǒng)管理。(函數(shù)調(diào)用時(shí)開(kāi)辟空間,函數(shù)調(diào)用結(jié)束時(shí)回收空間) - 棧是從
高地址向低地址擴(kuò)展,是一塊連續(xù)的內(nèi)存區(qū)域,遵循FILO先進(jìn)后出原則,效率高。 - 棧區(qū)一般在
運(yùn)行時(shí)進(jìn)行分配
緩沖區(qū)域
棧區(qū)和堆區(qū)中間有小塊未使用的內(nèi)存區(qū)域。用于給棧區(qū)和堆區(qū)之間創(chuàng)建一個(gè)緩沖區(qū)域
-
溢出:
到達(dá)緩沖區(qū)的數(shù)據(jù)向小緩沖區(qū)復(fù)制的過(guò)程中,由于沒(méi)有注意小緩沖區(qū)的邊界,導(dǎo)致小緩存區(qū)滿了,從而覆蓋了和小緩存區(qū)相鄰內(nèi)存區(qū)域的其他數(shù)據(jù)而引起的內(nèi)存問(wèn)題。
(就像桶盛水,水多了,自然越界溢出來(lái)了。)
1.2 堆區(qū)
- 空間最大,由我們手動(dòng)管理。(ARC自動(dòng)管理)
- 堆是從
低地址向高地址擴(kuò)展。 -
malloc、calloc、realloc開(kāi)辟: 堆區(qū)開(kāi)辟空間,可以是不連續(xù)的內(nèi)存區(qū)域,以鏈表結(jié)構(gòu)存在(增刪快,查找慢)。返回首地址存放在棧區(qū)。 -
free回收。釋放對(duì)象在堆區(qū)的內(nèi)存,并將棧中的地址指針置空。
需要注意:
-
野指針:提前釋放了,查詢時(shí)找不到內(nèi)容 -
內(nèi)存泄露:沒(méi)有釋放,一直占用內(nèi)存 -
過(guò)度釋放:對(duì)已釋放的對(duì)象進(jìn)行release操作。
1.3 全局靜態(tài)區(qū)(.bss)
- 存放
全局變量和靜態(tài)變量 - 空間由
系統(tǒng)管理。(程序啟動(dòng)時(shí),開(kāi)辟空間;程序結(jié)束時(shí),回收空間;程序執(zhí)行期間一直存在) -
static修飾的變量僅執(zhí)行一次,生命周期為整個(gè)程序運(yùn)行期
1.4 常量區(qū)(.data)
- 存放常量(
整型、字符型,浮點(diǎn),字符串等),整個(gè)程序運(yùn)行期不能被改變。 - 空間由
系統(tǒng)管理,生命周期為整個(gè)程序運(yùn)行期。
1.5 代碼區(qū)(.text)
- 存放
程序執(zhí)行的CPU指令。(編譯期將代碼轉(zhuǎn)換為CPU指令)
define和const區(qū)別:
define: 宏。編譯期不會(huì)進(jìn)行語(yǔ)法識(shí)別,沒(méi)有類型。編譯期會(huì)分配內(nèi)存。每次使用都會(huì)進(jìn)行宏替換和開(kāi)辟內(nèi)存。
const: 常量。編譯期會(huì)進(jìn)行語(yǔ)法識(shí)別,需要指定類型。編譯期不會(huì)分配內(nèi)存,僅在第一次使用時(shí),開(kāi)辟內(nèi)存并記錄內(nèi)存地址。后續(xù)調(diào)用時(shí)不會(huì)開(kāi)辟內(nèi)存,直接返回記錄的內(nèi)存地址。效率更快。內(nèi)存占用更少。
可以通過(guò)以下代碼,加深印象:
- (void)test {
NSInteger i = 666;
NSLog(@"NSInteger i -> 內(nèi)存地址:%p", &i); // 【局部變量】 棧區(qū)
NSString * name = @"HT";
NSLog(@"NSString name -> 內(nèi)存地址: %p", name); // 【字符串內(nèi)容】 存放在常量區(qū)
NSLog(@"NSString name -> 指針地址: %p", &name);// 【局部變量name的指針】 存放在棧區(qū)
NSObject * objc = [NSObject new];
NSLog(@"NSObject objc -> 內(nèi)存地址: %p", objc);// 【對(duì)象的內(nèi)容】 存放在堆區(qū)
NSLog(@"NSObject objc -> 指針地址: %p", &objc);//【對(duì)象的指針】 存放在棧區(qū)
}
- 打印結(jié)果: (
0x7開(kāi)頭:棧區(qū)、0x1開(kāi)頭:常量區(qū)、0x6開(kāi)頭:堆區(qū))
image.png
2. 多線程
官方文檔: ?? 相關(guān)鏈接
1. 線程和進(jìn)程的定義
- 線程:
-
線程是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程的所有任務(wù)都在線程中執(zhí)行 -
進(jìn)程想要執(zhí)行任務(wù),必須得有線程,進(jìn)程至少要有一條線程 -
程序啟動(dòng)會(huì)默認(rèn)開(kāi)啟一條線程,這條線程被稱為主線程或UI線程
- 進(jìn)程:
-
進(jìn)程是指在系統(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)中所開(kāi)啟的線程。
image.png
2. 線程與進(jìn)程的關(guān)系
-
地址空間:
同一進(jìn)程的線程共享本進(jìn)程的地址空間,而進(jìn)程之間則是獨(dú)立的地址空間。 -
資源擁有:
同一進(jìn)程內(nèi)的線程共享本進(jìn)程內(nèi)的資源(如內(nèi)存、I/O、cpu等),但進(jìn)程之間資源是相互獨(dú)立的。
-
進(jìn)程崩潰后,保護(hù)模式下不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響,但一個(gè)線程崩潰會(huì)導(dǎo)致整個(gè)進(jìn)程都死掉。所以多進(jìn)程比多線程健壯。 -
進(jìn)程切換時(shí),消耗的資源大。涉及頻繁切換時(shí),使用線程要好過(guò)于進(jìn)程。同樣要求同時(shí)進(jìn)行且共享某些變量的并發(fā)操作時(shí),只能用線程不能用進(jìn)程。 -
執(zhí)行過(guò)程:每個(gè)獨(dú)立的進(jìn)程都有一個(gè)程序運(yùn)行入口和順序執(zhí)行序列。但是線程不能獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。 -
線程是處理器調(diào)度的基本單位,但進(jìn)程不是。 -
線程沒(méi)有地址空間,線程包含在進(jìn)程地址空間中。
3. 多線程的意義
- 優(yōu)點(diǎn):
- 適當(dāng)提高
執(zhí)行效率 - 適當(dāng)提高
資源的利用率(CPU、內(nèi)存等) - 線程上的
任務(wù)執(zhí)行完后,線程會(huì)自動(dòng)銷毀
- 缺點(diǎn):
-
開(kāi)啟線程需要占用一定的內(nèi)存空間(參照下面 第5點(diǎn) 線程成本 ) - 開(kāi)啟大量線程,會(huì)
占用大量內(nèi)存空間,降低程序性能 -
線程越多,CPU在調(diào)度線程上的開(kāi)銷越大 - 程序
設(shè)計(jì)更加復(fù)雜(如線程間的通訊,多線程的數(shù)據(jù)共享等)
4. 時(shí)間片
時(shí)間片的概念: CPU在多個(gè)任務(wù)之間進(jìn)行快速切換,這個(gè)時(shí)間間隔就是時(shí)間片。
(
單核CPU)同一時(shí)間,CPU只能處理1個(gè)線程多線程同時(shí)執(zhí)行:
理論上,只要CPU在多個(gè)線程切換的足夠快(時(shí)間片足夠小),就可以做出"同時(shí)執(zhí)行"的假象。
(但實(shí)際上,一個(gè)CPU單次只對(duì)一個(gè)線程進(jìn)行調(diào)度。所以多線程同步需要多個(gè)CPU的處理器(多核)才可以做到。)如果
線程數(shù)非常多,CPU在多個(gè)線程之間切換,會(huì)消耗大量CPU資源。
每個(gè)線程被調(diào)度的次數(shù)會(huì)降低,線程的執(zhí)行效率會(huì)降低
5. 線程成本

- 谷歌翻譯:

-
內(nèi)核數(shù)據(jù)結(jié)構(gòu): 1KB -
堆空間:iOS主線程:1MB,OSX主線程:8MB、其他輔助線程:512KB -
創(chuàng)建時(shí)間:平均90微妙
6. 多線程技術(shù)方案

1. pthread
pthread是一套通用的多線程 API,可以在Unix/ Linux / Windows 等系統(tǒng)跨平臺(tái)使用,使用 C 語(yǔ)言編寫(xiě),需要程序員自己管理線程的生命周期,使用難度較大,我們?cè)?iOS 開(kāi)發(fā)中幾乎不使用。
- 簡(jiǎn)單使用實(shí)例:
#import <pthread.h>
- (void)createThread {
// 1. 創(chuàng)建線程:定義一個(gè)pthread_t類型變量
pthread_t thread;
// 2. 開(kāi)啟線程:執(zhí)行任務(wù)
// 參數(shù)1: 要開(kāi)的線程變量
// 參數(shù)2:線程的屬性
// 參數(shù)3:子線程的執(zhí)行函數(shù)(任務(wù))
// 參數(shù)4:函數(shù)入?yún)? pthread_create(&thread, NULL, run, @"入?yún)?);
// 3. 設(shè)置子線程的狀態(tài)設(shè)置為detached,該線程運(yùn)行結(jié)束后會(huì)自動(dòng)釋放所有資源
pthread_detach(thread);
}
void * run(void * param) {
NSLog(@"%@ %@", [NSThread currentThread], param);
return NULL;
}
- 打印結(jié)果:

- 其他方法:
pthread_create(): 創(chuàng)建一個(gè)線程
pthread_exit(): 終止當(dāng)前線程
pthread_cancel(): 中斷另外一個(gè)線程的運(yùn)行
pthread_join():阻塞當(dāng)前的線程,直到另外一個(gè)線程運(yùn)行結(jié)束
pthread_attr_init():初始化線程的屬性
pthread_attr_setdetachstate():設(shè)置脫離狀態(tài)的屬性(決定這個(gè)線程在終止時(shí)是否可以被結(jié)合)
pthread_attr_getdetachstate():獲取脫離狀態(tài)的屬性
pthread_attr_destroy(): 刪除線程的屬性
pthread_kill(): 向線程發(fā)送一個(gè)信號(hào)
2. NSThread
NSThread是蘋(píng)果官方提供的,使用起來(lái)比pthread更加面向?qū)ο?,?jiǎn)單易用,可直接操作線程對(duì)象,需要自己管理線程生命周期。實(shí)際開(kāi)發(fā)中偶爾使用。
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self createThread1];
// [self createThread2];
// [self createThread3];
}
//MARK: - 創(chuàng)建線程
//創(chuàng)建線程 (手動(dòng)啟動(dòng))
-(void)createThread1{
// 實(shí)例化一個(gè)線程對(duì)象
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(run1) object:nil];
// 線程名稱
thread.name = @"Thread1Name";
/**
NSQualityOfServiceUserInteractive = 0x21, 用戶交互 - 最高(21)
NSQualityOfServiceUserInitiated = 0x19, 用戶馬上執(zhí)行的事件 - 較高(19)
NSQualityOfServiceUtility = 0x11, 普通任務(wù) - 普通(11)
NSQualityOfServiceBackground = 0x09, 后臺(tái)任務(wù) - 較低 (9)
NSQualityOfServiceDefault = -1 常規(guī) - 最低
*/
// 線程優(yōu)先級(jí)
thread.qualityOfService = NSQualityOfServiceDefault;
// 線程啟動(dòng)
[thread start];
}
//創(chuàng)建線程 (自動(dòng)啟動(dòng))
-(void)createThread2{
//創(chuàng)建線程后自動(dòng)啟動(dòng)線程
[NSThread detachNewThreadSelector:@selector(run2:) toTarget:self withObject:@"createThread2"];
}
//創(chuàng)建線程 (自動(dòng)啟動(dòng))
-(void)createThread3{
//隱式創(chuàng)建線程并啟動(dòng)
[self performSelectorInBackground:@selector(run2:) withObject:@"createThread3"];
}
//MARK: - 耗時(shí)操作
- (void)run1{
for (int i=0; i<200; i++) {
NSLog(@"%d----%@",i,[NSThread currentThread]);
}
}
- (void)run2:(NSString*)param{
for (int i=0; i<200; i++) {
NSLog(@"%d----%@---%@",i,[NSThread currentThread],param);
}
}
- 創(chuàng)建:
-
createThread1:手動(dòng)啟動(dòng)線程,可以配置線程屬性(名稱、優(yōu)先級(jí)); -
createThread2:自動(dòng)啟動(dòng)線程,快捷便利,不支持配置線程屬性; -
createThread3:隱式創(chuàng)建線程并啟動(dòng),快捷便利,不支持配置線程屬性;
- 任務(wù):
run1無(wú)參數(shù),run2帶參數(shù)
其他方法:
+ (NSThread *)mainThread: 獲得主線程
- (BOOL)isMainThread: 判斷是否為主線程(對(duì)象方法)
+ (BOOL)isMainThread: 判斷是否為主線程(類方法)
NSThread *current = [NSThread currentThread]: 獲得當(dāng)前線程
- (void)setName:(NSString *)n: 線程的名字——setter方法
- (NSString *)name: 線程的名字——getter方法
- (BOOL)isCancelled:判斷是否已取消
- (BOOL)isFinished:判斷是否已經(jīng)結(jié)束
- (BOOL)isExecuting:判斷是否正在執(zhí)行狀態(tài)控制方法:
- (void)start:線程進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)。當(dāng)線程任務(wù)執(zhí)行完畢,自動(dòng)進(jìn)入死亡狀態(tài)
- (void)cancel: 線程取消
- (void)setName:(NSString *)n: 線程的名字——setter方法
+ (void)sleepUntilDate:(NSDate *)date:阻塞(暫停)線程方法
+ (void)sleepForTimeInterval:(NSTimeInterval)ti:線程進(jìn)入阻塞狀態(tài)
+ (void)exit:線程進(jìn)入死亡狀態(tài)(立即終止除主線程以外所有線程)線程之間的通信:
在主線程上執(zhí)行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array
在指定線程上執(zhí)行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
在當(dāng)前線程上執(zhí)行操作,調(diào)用 NSObject 的 performSelector:相關(guān)方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
- 售票案例(
線程安全,多讀單寫(xiě))
@interface ViewController ()
@property (nonatomic, assign) NSInteger ticketSurplusCount; // 剩余票數(shù)
@property (nonatomic, strong) NSThread *ticketSaleWindow1; // 線程1
@property (nonatomic, strong) NSThread *ticketSaleWindow2; // 線程2
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initTicketStatusSave];
}
/**
* 初始化火車票數(shù)量、賣票窗口(線程安全)、并開(kāi)始賣票
*/
- (void)initTicketStatusSave {
// 1. 設(shè)置剩余火車票為 50
self.ticketSurplusCount = 50;
// 2. 設(shè)置北京火車票售賣窗口的線程
self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
self.ticketSaleWindow1.name = @"北京火車票售票窗口";
// 3. 設(shè)置上?;疖嚻笔圪u窗口的線程
self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
self.ticketSaleWindow2.name = @"上?;疖嚻笔燮贝翱?;
// 4. 開(kāi)始售賣火車票
[self.ticketSaleWindow1 start];
[self.ticketSaleWindow2 start];
}
/**
* 售賣火車票(線程安全)
*/
- (void)saleTicketSafe {
while (1) {
// 互斥鎖
@synchronized (self) {
//如果還有票,繼續(xù)售賣
if (self.ticketSurplusCount > 0) {
self.ticketSurplusCount --;
NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
[NSThread sleepForTimeInterval:0.2];
}
//如果已賣完,關(guān)閉售票窗口
else {
NSLog(@"所有火車票均已售完");
break;
}
}
}
}
3. GCD
- GCD(
Grand Central Dispatch),大中央調(diào)度。
對(duì)線程操作進(jìn)行了封裝,加入了很多新的特性,內(nèi)部進(jìn)行了效率優(yōu)化,提供了簡(jiǎn)潔的C語(yǔ)言接口,使用簡(jiǎn)單高效,是蘋(píng)果推薦的方式。使用頻率高。
#pragma mark - GCD演練
/**
并發(fā)隊(duì)列,同步執(zhí)行
*/
- (void)gcdDemo4 {
// 1. 隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_CONCURRENT);
// 2. 同步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
并發(fā)隊(duì)列,異步執(zhí)行
*/
- (void)gcdDemo3 {
// 1. 隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_CONCURRENT);
// 2. 異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
串行隊(duì)列,異步執(zhí)行
*/
- (void)gcdDemo2 {
// 1. 隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("itcast", NULL);
// 2. 異步執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
串行隊(duì)列,同步執(zhí)行(開(kāi)發(fā)中非常少用)
*/
- (void)gcdDemo1 {
// 1. 隊(duì)列
// dispatch_queue_t queue = dispatch_queue_create("icast", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("icast", NULL);
NSLog(@"執(zhí)行前----");
// 執(zhí)行任務(wù)
for (int i = 0; i < 10; i++) {
NSLog(@"調(diào)度----");
// 在隊(duì)列中"同步"執(zhí)行任務(wù),串行對(duì)列添加同步執(zhí)行任務(wù),會(huì)立即被執(zhí)行
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
NSLog(@"for 后面");
}
4. NSOperation
NSOperation是基于GCD的一個(gè)抽象基類,將線程封裝成要執(zhí)行的操作,不需要管理線程的生命周期和同步,但比GCD可控性更強(qiáng)。例如可以加入操作依賴(addDependency)、設(shè)置操作隊(duì)列最大可并發(fā)執(zhí)行的操作個(gè)數(shù)(setMaxConcurrentOperationCount)、取消操作(cancel)等。
NSOperation作為抽象基類不具備封裝我們的操作的功能,需要使用兩個(gè)它的實(shí)體子類:NSBlockOperation和NSInvocationOperation,或者繼承NSOperation自定義子類。
NSBlockOperation和NSInvocationOperation用法的主要區(qū)別是:前者執(zhí)行指定的方法,后者執(zhí)行代碼塊,相對(duì)來(lái)說(shuō)后者更加靈活易用。NSOperation操作配置完成后便可調(diào)用start函數(shù)在當(dāng)前線程執(zhí)行,如果要異步執(zhí)行避免阻塞當(dāng)前線程則可以加入NSOperationQueue中異步執(zhí)行。
- 測(cè)試代碼
- (void)opDemo2 {
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
NSLog(@"耗時(shí)操作 %@", [NSThread currentThread]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"更新UI %@", [NSThread currentThread]);
}];
}];
}
- (void)opDemo1 {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"Invocation"];
// start 會(huì)立即在當(dāng)前線程執(zhí)行 selector 方法
// [op start];
// 將操作添加到隊(duì)列,會(huì)自動(dòng)異步執(zhí)行
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperation:op];
}
- (void)downloadImage:(id)obj {
NSLog(@"%@ %@", [NSThread currentThread], obj);
}
7. 線程生命周期

-
新建:
new新建線程后,調(diào)用start后,并不會(huì)立即執(zhí)行,而是進(jìn)入就緒狀態(tài),等待CPU的調(diào)度。
-
新建:
-
運(yùn)行:
CPU調(diào)度當(dāng)前線程,進(jìn)入運(yùn)行狀態(tài),開(kāi)始執(zhí)行任務(wù)。
如果當(dāng)前線程還在運(yùn)行中,CPU從可調(diào)度池中調(diào)用其他線程,來(lái)執(zhí)行此任務(wù)。
-
運(yùn)行:
-
阻塞:
運(yùn)行中的任務(wù),被調(diào)用sleep/等待同步鎖時(shí),會(huì)進(jìn)入阻塞狀態(tài)。所有線程都停止,等待sleep結(jié)束/獲取同步鎖,才會(huì)回到就緒狀態(tài)。
-
阻塞:
-
死亡:
運(yùn)行中的任務(wù),在任務(wù)執(zhí)行完或被強(qiáng)制退出時(shí),線程自動(dòng)進(jìn)入Dead銷毀。
-
死亡:
線程池調(diào)度:

飽和策略:

3. 互斥鎖與自旋鎖
- 互斥鎖:
- 保證
鎖內(nèi)代碼,同一時(shí)間,只有一條線程能夠執(zhí)行; - 互斥鎖的
鎖定范圍,應(yīng)該盡量小,鎖定范圍越大,效率越差
- 互斥鎖參數(shù):
- 能夠
加鎖的任意NSObject對(duì)象 -
鎖對(duì)象要保證所有線程都能夠訪問(wèn) - 如果代碼只有
一個(gè)地方需要加鎖,大多都使用self,這樣可以避免單獨(dú)再創(chuàng)建一個(gè)鎖對(duì)象
-
自旋鎖:
耗性能,循環(huán)輪循是否可執(zhí)行。自旋鎖內(nèi)容應(yīng)盡可能小,保障盡快完成鎖內(nèi)任務(wù)。
互斥鎖與自旋鎖的區(qū)別:
互斥鎖是被動(dòng)等待代碼觸發(fā),再上鎖。自旋鎖是主動(dòng)輪循請(qǐng)求資源。所以自旋鎖更消耗資源。
- 要求
立即執(zhí)行,任務(wù)資源較小(執(zhí)行耗時(shí)短)時(shí),可選擇自旋鎖。被動(dòng)觸發(fā),任務(wù)資源較大(執(zhí)行耗時(shí)長(zhǎng))時(shí),選擇互斥鎖。
4. atomic與nonatomic的區(qū)別
nonatomic:
非原子屬性。非線程安全,適合內(nèi)存小的移動(dòng)設(shè)備。atomic
原子屬性。線程安全,需要消耗大量的資源。是默認(rèn)值。
atomic是針對(duì)多線程設(shè)計(jì)的,本身有自旋鎖, 實(shí)現(xiàn)單寫(xiě)多讀:?jiǎn)蝹€(gè)線程寫(xiě)入,多個(gè)線程可以讀取。
iOS官方建議:
所有屬性都聲明為nonatomic,避免多線程搶奪同一塊資源。
盡量將加鎖、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器端處理,減小移動(dòng)客戶端的壓力**
5. 線程與RunLoop
-
RunLoop與線程是一一對(duì)應(yīng)的,一個(gè)runloop對(duì)應(yīng)一個(gè)核心的線程。
為什么說(shuō)是核心的,是因?yàn)?code>runloop是可以嵌套的,但是
核心的只能有一個(gè),他們的關(guān)系保存在一個(gè)全局字典里。
Runloop是來(lái)管理線程的,當(dāng)線程的runloop被開(kāi)啟后,線程會(huì)在執(zhí)行完任務(wù)后進(jìn)入休眠狀態(tài),有任務(wù)就會(huì)被喚醒去執(zhí)行任務(wù)。Runloop在第一次獲取時(shí)被創(chuàng)建,在線程結(jié)束時(shí)被銷毀。對(duì)于
主線程來(lái)說(shuō),runloop在程序一啟動(dòng)就默認(rèn)創(chuàng)建好了。對(duì)于
子線程來(lái)說(shuō),runloop是懶加載的,只有當(dāng)我們使用時(shí)才會(huì)創(chuàng)建,所以在子線程用定時(shí)器要注意:確保子線程的runloop被創(chuàng)建,不然定時(shí)器不會(huì)回調(diào)。

