什么是多線程辛蚊?
要知道什么是多線程首先要了解進(jìn)程和線程的概念。
進(jìn)程:
指系統(tǒng)中正在運(yùn)行的應(yīng)用程序,而且每個(gè)進(jìn)程之間是相互獨(dú)立的
線程:
程序執(zhí)行的基本單元外邓,程序中的任務(wù)都在線程中執(zhí)行
線程中執(zhí)行任務(wù)的方式分為串行和并行,串行指所有任務(wù)按照順序依次執(zhí)行古掏,并行是指在一個(gè)線程中多個(gè)任務(wù)同時(shí)執(zhí)行
多線程:
在一個(gè)進(jìn)程中可以開辟多個(gè)線程來同時(shí)(并行)運(yùn)行损话,每個(gè)線程也可串行或并行執(zhí)行任務(wù)。但是CPU同一時(shí)間只能處理一條線程,多線程并發(fā)執(zhí)行其實(shí)是由于CPU運(yùn)行速度足夠快丧枪,在多條線程之間進(jìn)行調(diào)度光涂,造成了多條線程并發(fā)執(zhí)行的假象,如果有非常多的線程同時(shí)執(zhí)行拧烦,也許會(huì)造成CPU崩潰
多線程的優(yōu)缺點(diǎn):
多線程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
①能適當(dāng)提高程序的執(zhí)行效率
②能適當(dāng)提高資源利用率(CPU忘闻、內(nèi)存利用率)
缺點(diǎn):
①開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M恋博,子線程占用512KB)服赎,如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間交播,降低程序的性能
②線程越多重虑,CPU在調(diào)度線程上的開銷就越大
③程序設(shè)計(jì)更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享
iOS里面實(shí)現(xiàn)多線程的方案:
#######iOS中目前多線程有4套實(shí)現(xiàn)方案:
Pthread:
這是一套在很多操作系統(tǒng)上都通用的多線程API秦士,移植性很強(qiáng)缺厉。不過這是基于c語言的框架,使用起來有點(diǎn)困難隧土,對(duì)程序猿的技術(shù)要求略高
NSThread:
是相對(duì)輕量級(jí)的提针,但也是使用起來最負(fù)責(zé)的,你需要自己管理thread的生命周期曹傀,線程之間的同步辐脖。線程共享同一應(yīng)用程序的部分內(nèi)存空間,它們擁有對(duì)數(shù)據(jù)相同的訪問權(quán)限皆愉。
GCD:
Grand Central Dispatch (GCD)是Apple開發(fā)的一個(gè)多核編程的較新的解決方法嗜价。GCD是一個(gè)替代諸如NSThread等技術(shù)的很高效和強(qiáng)大的技術(shù)。GCD完全可以處理諸如數(shù)據(jù)鎖定和資源泄漏等復(fù)雜的異步編程問題幕庐。GCD的工作原理是讓一個(gè)程序久锥,根據(jù)可用的處理資源,安排他們?cè)谌魏慰捎玫奶幚砥骱诵纳掀叫信抨?duì)執(zhí)行特定的任務(wù)异剥。這個(gè)任務(wù)可以是一個(gè)功能或者一個(gè)程序段瑟由。這是iOS開發(fā)中最多使用的多線程實(shí)現(xiàn)方案
NSOperation:
NSOperation實(shí)際上是蘋果對(duì)GCD的封裝,相對(duì)于GCD來說可控性更高冤寿,NSOperation實(shí)際上是一個(gè)抽象的基類歹苦,并不能直接使用,需要通過繼承于它的子類來調(diào)用各種方法實(shí)現(xiàn)功能
簡(jiǎn)單實(shí)現(xiàn)
pthread:
首先當(dāng)然是導(dǎo)入頭文件
<pre><code>
import "pThread"
</code></pre>
假設(shè)我們有一耗時(shí)操作(寫成函數(shù)指針形式)
void *run(void *costTime) {
for (NSInteger i = 0; i < 10000; i++) {
NSLog(@"%ld", i)
}
}
這里我是設(shè)置一個(gè)Button的點(diǎn)擊事件來執(zhí)行
- (void)btnClick {
pthread_t pThread;
pthread_create(&pthread, NULL, run, NULL);
// 第一個(gè)參數(shù):線程指針
// 第二個(gè)參數(shù):線程的一些屬性
// 第三個(gè)參數(shù):用于執(zhí)行方法的函數(shù)指針
// 第四個(gè)參數(shù):線程中的傳值
}
這樣就創(chuàng)建了一條線程來執(zhí)行函數(shù)costTime督怜,主線程的任務(wù)可以繼續(xù)執(zhí)行殴瘦,不必等待
NSThread:
- (void)creadNSThread
{
// 創(chuàng)建線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(costTime) object:@"111"];
thread.name = @"222";
// 開啟線程
[thread start];
NSLog(@"%@", [NSThread currentThread]);//當(dāng)前線程
NSLog(@"%@", [NSThread mainThread]);//主線程
NSLog(@"%d", [NSThread isMainThread]);//是否為主線程
}
// 快捷創(chuàng)建方式
- (void)creatNSThread1
{
// 快捷創(chuàng)建 無返回值
[NSThread detachNewThreadSelector:@selector(costTime) toTarget:self withObject:nil];
}
NSOperation:
- (void)createNSOperation
{
NSInvocationOperation *operation_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction1) object:nil];
NSInvocationOperation *operation_2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction2) object:nil];
// block方式創(chuàng)建多線程
NSBlockOperation *operation_3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"第三個(gè) -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第三個(gè) -- %d", i);
}
}];
// 操作隊(duì)列
// 目的:將任務(wù)放在一個(gè)隊(duì)列中執(zhí)行
// 任務(wù):任務(wù)執(zhí)行在主線程還是在子線程全部都是由我們的隊(duì)列來決定的
// 獲取主隊(duì)列
// NSOperationQueue *queue = [NSOperationQueue mainQueue];
// alloc init 的代表字其他隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 先加入隊(duì)列的先執(zhí)行,但是執(zhí)行的時(shí)間不定亮蛔,可能后執(zhí)行的比先執(zhí)行的先執(zhí)行完
[queue addOperation:operation_1];
[queue addOperation:operation_2];
[queue addOperation:operation_3];
}
- (void)operationAction1
{
NSLog(@"第一個(gè) -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第一個(gè) -- %d", i);
}
}
- (void)operationAction2
{
NSLog(@"第二個(gè) -- %d", [NSThread isMainThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"第二個(gè) -- %d", i);
}
}
GCD:
- (void)viewDidLoad {
[super viewDidLoad];
// 下面這種方式中痴施,最內(nèi)層的任務(wù)永遠(yuǎn)不會(huì)執(zhí)行擎厢,因?yàn)槿蝿?wù)2要等待任務(wù)執(zhí)行完才會(huì)執(zhí)行究流,而任務(wù)2又在任務(wù)1中辣吃,造成類似死循環(huán)
// 所以這里是一個(gè)錯(cuò)誤演示
dispatch_queue_t queue = dispatch_queue_create("sss", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1 --- %@", [NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"2 --- %@", [NSThread currentThread]);
});
});
}
實(shí)現(xiàn):
根據(jù)GCD執(zhí)行方式,可將其分為幾種類型
根據(jù)線程執(zhí)行方式分為同步:同一個(gè)線程順序執(zhí)行 異步:不在一個(gè)線程執(zhí)行
根據(jù)任務(wù)執(zhí)行方式串行:串在一起執(zhí)行 并行:一起執(zhí)行
主隊(duì)列不會(huì)開辟新的線程芬探,所以使用主線程執(zhí)行任務(wù)只有同步串行一種方式
// 此處只實(shí)現(xiàn)異步并發(fā)方式
// 異步 + 并發(fā)隊(duì)列 具備開啟子線程的能力神得,并且并發(fā)執(zhí)行任務(wù)
- (void)createAsyncConcurrent
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1 --- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3 --- %@", [NSThread currentThread]);
});
}