了解多線程之前首先要了解一下幾個(gè)概念
進(jìn)程
進(jìn)程是指在系統(tǒng)中正在進(jìn)行的一個(gè)應(yīng)用程序;每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi)。
線程
一個(gè)進(jìn)程要想執(zhí)行任務(wù),必須得有線程(每一個(gè)進(jìn)程至少要有一條線程)笋粟,是進(jìn)程中執(zhí)行運(yùn)算的最小單位,是進(jìn)程中的一個(gè)實(shí)體析蝴,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位;
多線程
進(jìn)程中可以開啟多條線程害捕,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù)。多線程技術(shù)可以提高程序的執(zhí)行效率闷畸。
多線程原理
單核CPU同一時(shí)間內(nèi)能處理1條線程尝盼,多線程并發(fā)執(zhí)行,其實(shí)是CPU快速地在多條線程之間調(diào)度佑菩。如果CPU調(diào)度線程的時(shí)間足夠快盾沫,就造成了多線程并發(fā)執(zhí)行的假象。
多線程的優(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ù)共享鞠眉。
同步和異步的區(qū)別
同步:只能在當(dāng)前線程中執(zhí)行任務(wù)薯鼠,不具備開啟新線程的能力
異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
并發(fā)和串行
并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
串行:一個(gè)任務(wù)執(zhí)行完畢后械蹋,再執(zhí)行下一個(gè)任務(wù)
線程間怎么通信
NSThread
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
- (void)updateUI {
// UI更新代碼
self.alert.text = @"Thanks!";
}
NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// UI更新代碼
self.alert.text = @"Thanks!";
}];
GCD
dispatch_async(dispatch_get_main_queue(), ^{
// UI更新代碼
self.alert.text = @"Thanks!";
});
多線程在ios中的運(yùn)用
NSThread的使用
NSThread創(chuàng)建線程
/** 方法一,需要start */
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething1:) object:@"NSThread1"];
// 線程加入線程池等待CPU調(diào)度羞芍,時(shí)間很快哗戈,幾乎是立刻執(zhí)行
[thread1 start];
- (void)doSomething1:(NSObject *)object {
// 傳遞過來的參數(shù)
NSLog(@"%@",object);
NSLog(@"doSomething1:%@",[NSThread currentThread]);
}
/** 方法二,創(chuàng)建好之后自動(dòng)啟動(dòng) */
[NSThread detachNewThreadSelector:@selector(doSomething2:) toTarget:self withObject:@"NSThread2"];
- (void)doSomething2:(NSObject *)object {
NSLog(@"%@",object);
NSLog(@"doSomething2:%@",[NSThread currentThread]);
}
/** 方法三荷科,隱式創(chuàng)建唯咬,直接啟動(dòng) */
[self performSelectorInBackground:@selector(doSomething3:) withObject:@"NSThread3"];
- (void)doSomething3:(NSObject *)object {
NSLog(@"%@",object);
NSLog(@"doSomething3:%@",[NSThread currentThread]);
}
返回當(dāng)前線程
// 當(dāng)前線程
[NSThread currentThread];
NSLog(@"%@",[NSThread currentThread]);
阻塞休眠
//休眠多久
[NSThread sleepForTimeInterval:2];
//休眠到指定時(shí)間
[NSThread sleepUntilDate:[NSDate date]];
其他一些方法
//退出線程
[NSThread exit];
//判斷當(dāng)前線程是否為主線程
[NSThread isMainThread];
//判斷當(dāng)前線程是否是多線程
[NSThread isMultiThreaded];
//主線程的對(duì)象
NSThread *mainThread = [NSThread mainThread];
GCD的理解與使用
GCD中有2個(gè)核心概念
(1)任務(wù):執(zhí)行什么操作
(2)隊(duì)列:用來存放任務(wù)
隊(duì)列
不管是什么隊(duì)列,一定是FIFO隊(duì)列畏浆,即先進(jìn)先出胆胰。
所以,請(qǐng)大家記住了:不管是串行隊(duì)列(SerialQueue)還是并發(fā)隊(duì)列(ConcurrencyQueue)刻获,都是FIFO隊(duì)列蜀涨。也就意味著,任務(wù)一定是一個(gè)一個(gè)地蝎毡,按照先進(jìn)先出的順序來執(zhí)行厚柳。
串行隊(duì)列:
在創(chuàng)建隊(duì)列時(shí),傳參數(shù)DISPATCH_QUEUE_SERIAL表示創(chuàng)建串行隊(duì)列沐兵。任務(wù)會(huì)一個(gè)一個(gè)地執(zhí)行别垮,只有前一個(gè)任務(wù)執(zhí)行完成,才會(huì)繼續(xù)執(zhí)行下一個(gè)任務(wù)扎谎。串行執(zhí)行并不是同步執(zhí)行的意思碳想,一定要注意區(qū)分。
并發(fā)隊(duì)列:
在創(chuàng)建隊(duì)列時(shí)毁靶,傳參數(shù)DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建并發(fā)隊(duì)列胧奔。并發(fā)隊(duì)列會(huì)盡可能多地創(chuàng)建線程去執(zhí)行任務(wù)。并發(fā)隊(duì)列中的任務(wù)會(huì)按入隊(duì)的順序執(zhí)行任務(wù)老充,但是哪個(gè)任務(wù)先完成是不確定的葡盗。
串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("serial_queue",
DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"s1");
});
dispatch_async(serialQueue, ^{
sleep(2);
NSLog(@"s2");
});
dispatch_async(serialQueue, ^{
sleep(1);
NSLog(@"s3");
});
打印 s1,s2,s3
并發(fā)隊(duì)列
dispatch_queue_t concurrencyQueue = dispatch_queue_create("com.huangyibiao.concurrency-queue",
DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrencyQueue, ^{
NSLog(@"s1");
});
dispatch_async(concurrencyQueue, ^{
sleep(2);
NSLog(@"s2");
});
dispatch_async(concurrencyQueue, ^{
sleep(1);
NSLog(@"s3");
});
打印 s1,s3,s2
同步異步線程
// 全局并發(fā)隊(duì)列的獲取方法
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 同步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_sync(queue, ^{
// 這里放同步執(zhí)行任務(wù)代碼
});
// 異步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_async(queue, ^{
// 這里放異步執(zhí)行任務(wù)代碼
});