一澄峰、進(jìn)程
1.什么是進(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)
二俏竞、線程
1.什么是線程绸硕?
- 應(yīng)用程序中一條任務(wù)的執(zhí)行路徑
2.進(jìn)程和線程是什么關(guān)系堂竟?
- 一個(gè)進(jìn)程可以包含多個(gè)線程(一個(gè)進(jìn)程至少包含一個(gè)線程Main線程)
- 一個(gè)進(jìn)程中的所有任務(wù)都是在線程中執(zhí)行
3.線程中的任務(wù)怎么執(zhí)行?
- 如果要在一個(gè)線程中執(zhí)行多個(gè)任務(wù)玻佩,那么只能一個(gè)一個(gè)地按順序執(zhí)行這些任務(wù)出嘹,在同一時(shí)間內(nèi),一個(gè)線程只能執(zhí)行一個(gè)任務(wù)
- 比如在一個(gè)線程中下載三個(gè)文件A咬崔、B税稼、C,那么會(huì)先下載文件A垮斯,然后下載文件B郎仆,再下載文件C
4.什么是多線程
- 一個(gè)進(jìn)程中可以開啟多條線程,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù)
- 比如在一個(gè)線程中下載三個(gè)文件A兜蠕、B扰肌、C,開啟三條線程熊杨,每個(gè)線程下載一個(gè)文件曙旭,那么三個(gè)文件會(huì)同時(shí)去下載
5.多線程實(shí)現(xiàn)原理
- .同一時(shí)間,CPU只能處理1條線程晶府,只有1條線程在工作(執(zhí)行)
- .多線程并發(fā)(同時(shí))執(zhí)行桂躏,其實(shí)是CPU快速地在多條線程之間調(diào)度(切換)
- 如果CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程并發(fā)執(zhí)行
6.多線程的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)一:多線程技術(shù)可以提高程序的執(zhí)行效率
- 優(yōu)點(diǎn)二:能適當(dāng)提高資源利用率(CPU川陆、內(nèi)存利用率)
- 缺點(diǎn)一:大量使用多線程CPU會(huì)在N多線程之間調(diào)度沼头,消耗大量的CPU資源,每條線程被調(diào)度執(zhí)行的頻次會(huì)降低(線程的執(zhí)行效率降低)
- 缺點(diǎn)二:創(chuàng)建線程是有開銷的书劝,iOS下主要成本包括:內(nèi)核數(shù)據(jù)結(jié)構(gòu)(大約1KB)、椡林粒空間(子線程512KB购对、主線程1MB,也可以使用
-setStackSize:
設(shè)置陶因,但必須是4K的倍數(shù)骡苞,而且最小是16K),創(chuàng)建線程大約需要90毫秒的創(chuàng)建時(shí)間
三楷扬、iOS中多線程實(shí)現(xiàn)方案
四解幽、pthread
1.C語言API,使用比較麻煩
//開啟新的線程執(zhí)行run方法
- (void)pthread {
pthread_t thread;
pthread_create(&thread, NULL, run, NULL);
}
void * run(void *param){
for (NSInteger i = 0; i<50000; i++) {
NSLog(@"---------%zd", i);
}
return NULL;
}
五、NSThread
1.一個(gè)NSThread對(duì)象就代表一個(gè)線程,以下是幾種創(chuàng)建方式
- 第一種多線程方式烘苹,需要調(diào)用
start
方法才能啟動(dòng)
- (void)createThread1{
// 創(chuàng)建線程,線程對(duì)象(局部變量)系統(tǒng)會(huì)自己加持躲株,在任務(wù)執(zhí)行完之前不會(huì)被銷毀
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
thread.name = @"my-thread";
// 啟動(dòng)線程
[thread start];
}
- (void)run:(NSString *)param{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"------%@", [NSThread currentThread]);
}
}
- 第二種多線程方式,創(chuàng)建線程后自動(dòng)啟動(dòng)線程
- (void)createThread2{
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"rose"];
}
- (void)run:(NSString *)param{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"------%@", [NSThread currentThread]);
}
}
- 第三種多線程方式镣衡,隱式創(chuàng)建并啟動(dòng)線程
- (void)createThread3{
[self performSelectorInBackground:@selector(run:) withObject:@"jack"];
}
- (void)run:(NSString *)param{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"------%@", [NSThread currentThread]);
}
}
2.NSThread的線程通信
- 在一個(gè)線程中執(zhí)行完特定任務(wù)后霜定,轉(zhuǎn)到另一個(gè)線程繼續(xù)執(zhí)行任務(wù)档悠,一個(gè)線程傳遞數(shù)據(jù)給另一個(gè)線程,API如下:
- (void)performSelectorOnMainThread:(SEL)aSelector
withObject:(id)arg
waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector
onThread:(NSThread *)thread
withObject:(id)arg
waitUntilDone:(BOOL)wait;
- 線程通信示例:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self performSelectorInBackground:@selector(download3) withObject:nil];
}
//子線程下載圖片數(shù)據(jù)
- (void)download3{
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 回到主線程,顯示圖片
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
//[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
NSLog(@" --- waitUntilDone ---");
//waitUntilDone參數(shù):
//YES:會(huì)等到setImage方法走完以后打印最后一句log望浩。
//NO:在執(zhí)行setImage方法的時(shí)候不影響最后一句log的打印辖所,兩個(gè)是同時(shí)進(jìn)行
}
//主線程顯示圖片
- (void)showImage:(UIImage *)image{
self.imageView.image = image;
}
3.NSThread常用的方法
//獲得當(dāng)前線程
NSThread *current = [NSThread currentThread];
+ (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
+ (BOOL)isMainThread; // 是否為主線程
//線程的名字,適用于第一種方式創(chuàng)建的線程(創(chuàng)建的時(shí)候返回NSThread的對(duì)象)
- (void)setName:(NSString *)n;
- (NSString *)name;
六、GCD
1.什么是GCD
- 全稱是Grand Central Dispatch磨德,可譯為“重要的中樞調(diào)度器”
- GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
- GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核缘回、四核)
- GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)典挑、銷毀線程)
2.任務(wù):執(zhí)行什么操作
- 用同步的方式執(zhí)行任務(wù):
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
- 用異步的方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
- 同步和異步的區(qū)別
同步:只能在當(dāng)前線程中執(zhí)行任務(wù)酥宴,不具備開啟新線程的能力
異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
3.隊(duì)列
- 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
- 串行隊(duì)列(Serial Dispatch Queue)
讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后搔弄,再執(zhí)行下一個(gè)任務(wù))
- 獲取并發(fā)隊(duì)列
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列幅虑,供整個(gè)應(yīng)用使用,不需要手動(dòng)創(chuàng)建
使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 隊(duì)列的優(yōu)先級(jí)
unsigned long flags); // 此參數(shù)暫時(shí)無用顾犹,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發(fā)隊(duì)列
全局并發(fā)隊(duì)列的優(yōu)先級(jí)
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MI
//自己創(chuàng)建一個(gè)并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
- 獲取串行隊(duì)列
GCD中獲得串行有2種途徑
使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
dispatch_queue_t
dispatch_queue_create(const char *label, // 隊(duì)列名稱
dispatch_queue_attr_t attr); // 隊(duì)列屬性倒庵,一般用NULL即可,DISPATCH_QUEUE_SERIAL串行就傳NULL
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); // 創(chuàng)建
dispatch_release(queue); // 非ARC需要釋放手動(dòng)創(chuàng)建的隊(duì)列
使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
使用dispatch_get_main_queue()獲得主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
- 各種隊(duì)列和發(fā)送方法的組合
// 同步函數(shù) + 主隊(duì)列:(若是在主線程調(diào)用會(huì)卡死主線程)
- (void)syncMain{
NSLog(@"syncMain ----- begin");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
NSLog(@"syncMain ----- end");
}
// 異步函數(shù) + 主隊(duì)列:只在主線程中執(zhí)行任務(wù)
- (void)asyncMain{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
}
//同步函數(shù) + 串行隊(duì)列:不會(huì)開啟新的線程炫刷,在當(dāng)前線程執(zhí)行任務(wù)擎宝。任務(wù)是串行的,執(zhí)行完一個(gè)任務(wù)浑玛,再執(zhí)行下一個(gè)任務(wù)
- (void)syncSerial{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
}
//異步函數(shù) + 串行隊(duì)列:會(huì)開啟新的線程绍申,但是任務(wù)是串行的,執(zhí)行完一個(gè)任務(wù)顾彰,再執(zhí)行下一個(gè)任務(wù)
- (void)asyncSerial{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
}
//同步函數(shù) + 并發(fā)隊(duì)列:不會(huì)開啟新的線程
- (void)syncConcurrent{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
//會(huì)先執(zhí)行任務(wù)再執(zhí)行這句打印极阅,sync的任務(wù)會(huì)立刻執(zhí)行
NSLog(@"syncConcurrent--------end");
}
// 異步函數(shù) + 并發(fā)隊(duì)列:可以同時(shí)開啟多條線程
- (void)asyncConcurrent{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"1-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"2-----%@", [NSThread currentThread]);
}
});
//會(huì)先執(zhí)行這一句打印,再執(zhí)行添加到隊(duì)列里面的任務(wù)
NSLog(@"asyncConcurrent--------end");
}
-
各種組合圖示
- GCD中的實(shí)用方法
//1.延遲執(zhí)行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
//2.一次性代碼:使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});
//3.隊(duì)列組
//分別異步執(zhí)行2個(gè)耗時(shí)的操作,等2個(gè)異步操作都執(zhí)行完畢后涨享,再回到主線程執(zhí)行操作
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后筋搏,回到主線程...
});
//4.快速迭代
dispatch_apply(10, queue, ^(size_t index) {
//queue如果是串行隊(duì)列index是有順序的
//queue如果是并發(fā)隊(duì)列index是無序的(并發(fā)執(zhí)行)
});
//5.barrier函數(shù):保證barrier之前的任務(wù)是并發(fā)執(zhí)行,然后執(zhí)行barrier任務(wù)厕隧,然后執(zhí)行barrier之后的任務(wù)
- (void)barrier{
dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2-----%@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4-----%@", [NSThread currentThread]);
});
}
七奔脐、NSOperation
1.NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
- NSOperation和NSOperationQueue是對(duì)GCD的一層封裝
- NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
- 先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中
- 然后將NSOperation對(duì)象添加到NSOperationQueue中
- 系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來
- 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行
2.NSOperation:是個(gè)抽象類,并不具備封裝操作的能力吁讨,必須使用它的子類
- NSInvocationOperation
//默認(rèn)情況下滔悉,調(diào)用了start方法后并不會(huì)開一條新線程去執(zhí)行操作祝沸,而是在當(dāng)前線程同步執(zhí)行操作
//只有將NSOperation放到一個(gè)NSOperationQueue中,才會(huì)異步執(zhí)行操作
- (void)invocationOperation{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[op start];
}
- (void)run{
NSLog(@"------%@", [NSThread currentThread]);
}
- NSBlockOperation
//只要NSBlockOperation封裝的操作數(shù) > 1,就會(huì)異步執(zhí)行操作
- (void)blockOperation{
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主線程
NSLog(@"下載1------%@", [NSThread currentThread]);
}];
// 添加額外的任務(wù)(在子線程執(zhí)行)
[op addExecutionBlock:^{
NSLog(@"下載2------%@", [NSThread currentThread]);
}];
[op start];
}
3.NSOperationQueue
- NSOperation可以調(diào)用start方法來執(zhí)行任務(wù)版扩,但默認(rèn)是同步執(zhí)行的
- 如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中布讹,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperation中的操作
- 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;//添加op的時(shí)候會(huì)默認(rèn)調(diào)用[op start];
- (void)addOperationWithBlock:(void (^)(void))block;//會(huì)默認(rèn)調(diào)用[op start];
4.NSOperation和NSOperationQueue的組合使用
- NSInvocationOperation和NSOperationQueue
- (void)operationQueue1{
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 創(chuàng)建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
// 添加任務(wù)到隊(duì)列中
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op2]; // [op2 start]
}
- (void)download1{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}
- (void)download2{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}
- NSBlockOperation和NSOperationQueue的組合使用
- (void)operationQueue1{
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 創(chuàng)建NSBlockOperation
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download5 --- %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download6 --- %@", [NSThread currentThread]);
}];
// 添加任務(wù)到隊(duì)列中
[queue addOperation:op3]; // [op3 start]
[queue addOperation:op4]; // [op4 start]
}
5.如果控制NSOperationQueue是串行隊(duì)列還是并發(fā)隊(duì)列
- 默認(rèn)最大并發(fā)數(shù)是-1,也就是不限制最大并發(fā)數(shù),當(dāng)有多個(gè)任務(wù)的時(shí)候會(huì)開啟多條線程同時(shí)執(zhí)行任務(wù)
- maxConcurrentOperationCount:同時(shí)執(zhí)行的任務(wù)個(gè)數(shù)
- (void)maxConcurrentOperationCountTest {
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 變成了串行隊(duì)列,會(huì)開啟一條線程艰亮,任務(wù)依次執(zhí)行
queue.maxConcurrentOperationCount = 1;
// 添加操作
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}];
}
6.隊(duì)列的取消、暫停挣郭、恢復(fù)
- 取消隊(duì)列的所有操作
- (void)cancelAllOperations;
//也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作
- 暫停和恢復(fù)隊(duì)列
- (void)setSuspended:(BOOL)b; // YES代表暫停隊(duì)列迄埃,NO代表恢復(fù)隊(duì)列
- (BOOL)isSuspended;
7.操作的相互依賴:NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序
- 比如一定要讓操作A執(zhí)行完后,才能執(zhí)行操作B兑障,可以這么寫
[operationB addDependency:operationA]; // 操作B依賴于操作A
-
任務(wù)可以夸隊(duì)列依賴侄非,在不同隊(duì)列里面的任務(wù)也可以相互依賴
任務(wù)不可以相互依賴,會(huì)卡死:
[operationB addDependency:operationA]; // 操作B依賴于操作A
[operationA addDependency:operationB]; // 操作A依賴于操作B
八流译、線程狀態(tài)
1.線程狀態(tài)
- 創(chuàng)建一個(gè)線程調(diào)用了start方法以后線程對(duì)象會(huì)放入可調(diào)度線程池逞怨,進(jìn)入就緒狀態(tài),等待CPU的調(diào)度
- 當(dāng)CPU調(diào)度的時(shí)候處于runing狀態(tài)福澡,當(dāng)CPU調(diào)用其他線程的時(shí)候當(dāng)前線程會(huì)進(jìn)入就緒狀態(tài)
- 調(diào)用了sleep方法\等待同步鎖會(huì)進(jìn)入阻塞狀態(tài)
- sleep到時(shí)\得到同步鎖進(jìn)入就緒狀態(tài)
- 線程任務(wù)執(zhí)行完畢叠赦、異常\強(qiáng)制退出,進(jìn)入死亡狀態(tài)
2.線程狀態(tài)示意圖:
3.線程狀態(tài)相關(guān)方法
啟動(dòng)線程
- (void)start;
// 進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)革砸。當(dāng)線程任務(wù)執(zhí)行完畢除秀,自動(dòng)進(jìn)入死亡狀態(tài)
阻塞(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 進(jìn)入阻塞狀態(tài)
強(qiáng)制停止線程
+ (void)exit;
// 進(jìn)入死亡狀態(tài)
注意:一旦線程停止(死亡)了,就不能再次開啟任務(wù)
九算利、多線程資源搶奪
1.資源搶奪簡(jiǎn)述:
- 一塊資源可能會(huì)被多個(gè)線程共享册踩,也就是多個(gè)線程可能會(huì)訪問同一塊資源,比如多個(gè)線程訪問同一個(gè)對(duì)象效拭、同一個(gè)變量暂吉、同一個(gè)文件
- 當(dāng)多個(gè)線程訪問同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問題
2.資源搶奪示意圖:
3.線程同步(互斥鎖)
- 線程同步:多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù)),互斥鎖缎患,就是使用了線程同步技術(shù).
- 互斥鎖對(duì)某段代碼進(jìn)行加鎖
- 一個(gè)線程在進(jìn)入之前會(huì)判斷鎖的狀態(tài)是否是打開慕的,若果是打開則加鎖,然后進(jìn)入代碼進(jìn)行操作挤渔,操作完成后解鎖业稼。在操作過程中如果有其他線程想對(duì)這段代碼進(jìn)行操作則需要等待鎖放開才能進(jìn)入操作
- 互斥鎖雖然能有效解決多線程的資源搶奪問題,同時(shí)需要消耗大量的CPU資源
//注意:鎖定1份代碼只用1把鎖蚂蕴,用多把鎖是無效的(一般self即可)
@synchronized(鎖對(duì)象) {
// 需要鎖定的代碼
}
4.互斥鎖的原理
5.原子和非原子屬性
- OC在定義屬性時(shí)有nonatomic和atomic兩種選擇
- atomic:原子屬性,為setter方法加鎖,是線程安全的(默認(rèn)就是atomic)
- nonatomic:非原子屬性俯邓,不會(huì)為setter方法加鎖
十骡楼、多線程下載多圖片示例
多線程下載多圖片demo 密碼:94ts