0.0 簡(jiǎn)介
(1) 進(jìn)程和線程基本概念【查看活動(dòng)監(jiān)視器】
> 什么是進(jìn)程
a昧辽、是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序冠王;
b向挖、每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程運(yùn)行在其專用且受保護(hù)的內(nèi)存空間哪替;
> 什么是線程
a栋荸、一個(gè)進(jìn)程想要執(zhí)行任務(wù),必須得有線程(每個(gè)進(jìn)程至少要有一條線程)凭舶;
b晌块、線程是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程(程序)的所有任務(wù)都在線程中執(zhí)行帅霜;
> 線程的串行
a匆背、一個(gè)線程中任務(wù)的執(zhí)行是串行的(在一個(gè)線程中執(zhí)行多個(gè)任務(wù),那么只能一個(gè)一個(gè)的按順序執(zhí)行身冀,在同一時(shí)間內(nèi)钝尸,一個(gè)線程只能執(zhí)行一個(gè)任務(wù));
> 線程的并行
a搂根、一個(gè)進(jìn)程中可以開啟多條線程珍促,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù);
【例如在一個(gè)線程中下載3個(gè)文件是串行剩愧;同時(shí)開啟3條線程分別下載3個(gè)文件是并行】
> 多線程的原理
a猪叙、單核CPU:同一時(shí)間,CPU只能處理一條線程仁卷,只有一條線程在工作(執(zhí)行)穴翩;多線程并發(fā)(同時(shí))執(zhí)行,其實(shí)是CPU快速的在多條線程之間調(diào)度(切換/輪詢)锦积;CPU調(diào)度線程的時(shí)間足夠快藏否,看到的多線程并發(fā)(同時(shí))執(zhí)行的假象;
b充包、多核CPU
> 多線程優(yōu)缺點(diǎn)
a、優(yōu)點(diǎn):適當(dāng)提高程序的執(zhí)行效率;適當(dāng)提高資源利用率(CPU/內(nèi)存利用率)基矮;
b淆储、缺點(diǎn):開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M家浇,子線程占用512KB)本砰,如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間钢悲,降低程序的性能点额;
> iOS創(chuàng)建線程的方式
pthread/NSThread/GCD/NSOperation
pthread用法
IPHONE4: 512m
安卓: 2G
安卓(多進(jìn)程): Linux + JAVA虛擬機(jī) + 應(yīng)用程序
(QQ100M + 微信100M + UC瀏覽器100M + 游戲500M + 系統(tǒng)1G)
蘋果(多任務(wù)): 512M只有一個(gè)人用
1,NSThread
a,顯示創(chuàng)建alloc init會(huì)創(chuàng)建新的線程,需要手動(dòng)開啟start莺琳,線程可以設(shè)置名字name还棱。方法運(yùn)行結(jié)束,線程結(jié)束惭等。
2,b,隱式創(chuàng)建新線程珍手,自動(dòng)開啟
3,YES&&NO
1,YES即等待線程@selector操作做完才繼續(xù)執(zhí)行
2,NO即不等待線程線程操作完成
4,線程的生命周期:
? ? ? ? ? ? ?1,alloc+init:即創(chuàng)建對(duì)象,在運(yùn)行的內(nèi)存中辞做;
? ? ? ? ? ? 2,start:即線程為就緒態(tài) (萬事具備琳要,等待CPU);
? ? ? ? ? ? 3,當(dāng)CPU調(diào)度當(dāng)前線程:即線程為運(yùn)行態(tài)秤茅;
? ? ? ? ? ? 4當(dāng)CPU調(diào)度其他線程:即線程又回到就緒態(tài)稚补;
? ? ? ? ? ? 5,當(dāng)線程調(diào)用了sleep、等待同步鎖:即線程為阻塞態(tài)框喳;
? ? ? ? ? ? 6,當(dāng)線程中sleep完课幕、得到同步鎖:即線程變?yōu)榫途w態(tài);
? ? ? ? ? ? ?7,當(dāng)線程任務(wù)執(zhí)行完成/異常/強(qiáng)制退出:即線程為死亡態(tài)帖努;
5,線程安全 沒有加鎖撰豺,訪問的數(shù)據(jù)不是想要的
6,線程安全 沒有加鎖,訪問的數(shù)據(jù)不是想要的
7,線程安全 使用@synchronized加鎖拼余,訪問的數(shù)據(jù)是想要的
8,線程安全 使用NSLock加鎖污桦,訪問的數(shù)據(jù)是想要的
9,GCD簡(jiǎn)介
> 什么是GCD
a、全稱是Grand Center Dispatch匙监,即中樞調(diào)度器凡橱;
b、純C語(yǔ)言亭姥,提供了非常多強(qiáng)大的函數(shù)稼钩;
> GCD的優(yōu)勢(shì)
a、GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案达罗;
b坝撑、GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核静秆、四核);
c巡李、GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程抚笔、調(diào)度任務(wù)、銷毀線程)侨拦;
d殊橙、程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼狱从;
> GCD的2個(gè)核心概念
a膨蛮、任務(wù):執(zhí)行什么操作(執(zhí)行下載、播放音樂等)季研;
b敞葛、隊(duì)列:用來存放任務(wù);
> GCD的使用步驟
a训貌、定制任務(wù)[確定想要做的事情]制肮;
b、將任務(wù)添加到隊(duì)列中[GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出递沪,放到對(duì)應(yīng)線程中執(zhí)行豺鼻;另外任務(wù)的取出是遵循隊(duì)列的FIFO原則:先進(jìn)先出];
> GCD基本使用
a款慨、GCD中的2個(gè)用來執(zhí)行任務(wù)的函數(shù)
// 同步方式執(zhí)行任務(wù)[queue隊(duì)列儒飒,block任務(wù)]
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// 異步方式執(zhí)行任務(wù)[queue隊(duì)列,block任務(wù)]
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
b檩奠、GCD同步和異步的區(qū)別
- 同步:只能在當(dāng)前線程中執(zhí)行任務(wù)桩了,不具備開啟新線程的能力;
- 異步:可以在新的線程中執(zhí)行任務(wù)埠戳,具備可啟新線程的能力井誉;
[具備開啟線程的能力,但不代表一定會(huì)開啟線程U浮?攀ァ!]
c屁使、GCD隊(duì)列的兩大類型
- 并發(fā)隊(duì)列
多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))在岂;
并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效;
- 串行隊(duì)列
多個(gè)任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后蛮寂,再執(zhí)行下一個(gè)任務(wù))蔽午;
d、容易混淆的術(shù)語(yǔ)[同步酬蹋、異步及老、并發(fā)抽莱、串行]
- 同步和異步主要影響:具不具備開啟新的線程 (并不代表一定會(huì)開線程!);
- 并行和串行主要影響:任務(wù)的執(zhí)行方式骄恶;
e岸蜗、并行隊(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(long identifier, // 隊(duì)列的優(yōu)先級(jí)
unsigned long flags); // 參數(shù)保留,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發(fā)隊(duì)列
- 全局并發(fā)隊(duì)列的優(yōu)先級(jí)
DISPATCH_QUEUE_PRIORITY_HIGH? ? ? 高
DISPATCH_QUEUE_PRIORITY_DEFAULT? ? 默認(rèn)(中)
DISPATCH_QUEUE_PRIORITY_LOW? ? ? ? 低
DISPATCH_QUEUE_PRIORITY_BACKGROUND 后臺(tái)
f年缎、串行隊(duì)列
- 使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
- 使用dispatch_get_main_queue()獲得主隊(duì)列(跟主線程相關(guān)的隊(duì)列悔捶,用于線程間通信)
[主隊(duì)列是GCD自帶的一種特殊串行隊(duì)列;放在主隊(duì)列中的任務(wù)单芜,都會(huì)放到主線程中執(zhí)行]
GCD蜕该、延時(shí)執(zhí)行
/** 方式1,這種延時(shí)操作是不可取的洲鸠,因?yàn)檠訒r(shí)操作是在主線程堂淡,即會(huì)卡住主線程,如果sleep在其他線程則也會(huì)卡住對(duì)應(yīng)線程*/
? 方式1 ? 延時(shí)3秒[NSThread sleepForTimeInterval:3];
? 方式2 ? 定制好任務(wù)后扒腕,不會(huì)卡住當(dāng)前線程
[self performSelector:@selector(downloadImage) withObject:nil afterDelay:3];
?方式3 ?dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"圖片下載");
});
> GCD中線程間的通信
> GCD一次性代碼只執(zhí)行一次
10,總結(jié)
11,異步+并發(fā) 開啟新線程 多個(gè)任務(wù)同時(shí)執(zhí)行
12,異步+串行 開啟新線程 任務(wù)依次同時(shí)執(zhí)行
13,同步+并發(fā) 不開啟新線程 任務(wù)依次執(zhí)行
14,同步+串行 不開新線程 任務(wù)依次執(zhí)行
15,異步+主隊(duì)列 不開啟新線程 任務(wù)依次執(zhí)行(主隊(duì)列任務(wù)是一次執(zhí)行的绢淀,并且是異步)
16,同步+主隊(duì)列 不開啟新線程 任務(wù)依次執(zhí)行(堅(jiān)決反對(duì)使用這個(gè),容易卡)
17瘾腰,pthread
18皆的,NSOperation(基于GCD封裝)
> NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟:
a、將需要執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中蹋盆;
b费薄、然后將NSOperation對(duì)象添加到NSOperationQueue中;
c栖雾、系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來楞抡;
d、將取出來的NSOperation封裝的操作放到一條新線程中執(zhí)行析藕;
【系統(tǒng)會(huì)自動(dòng)處理召廷,不用管多少條線程】
> NSOperation的基本使用
a、NSOperation是抽象類噪径,不具備封裝操作的能力柱恤,必須使用它的子類;
b找爱、使用NSOperation子類的方式有3種
- 1梗顺,NSInvocationOperation
- 2,NSBlockOperation
- 3车摄,自定義子類繼承NSOperation寺谤,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
> NSInvocationOperation
?創(chuàng)建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage) object:nil];
> NSBlockOperation
沒有添加到隊(duì)列中仑鸥,直接調(diào)用operation的start方法
當(dāng)任務(wù)個(gè)數(shù)為一的時(shí)候,就是同步執(zhí)行;
當(dāng)任務(wù)個(gè)數(shù)大于一的時(shí)候变屁,就會(huì)異步執(zhí)行;
手動(dòng)開啟 (沒有添加到隊(duì)列中眼俊,就需要手動(dòng)開啟)
[operation start];
添加到隊(duì)列中 [自動(dòng)異步執(zhí)行]
[queue addOperation:operation];
> NSOperationQueue
1、創(chuàng)建一個(gè)隊(duì)列(非主隊(duì)列)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
2粟关、任務(wù)任務(wù)
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operation1? ? ? 下載圖片---%@",[NSThread currentThread]);
}];
[operation1 addExecutionBlock:^{
NSLog(@"operation2? ? ? 下載圖片---%@",[NSThread currentThread]);
}];
3疮胖、添加到隊(duì)列中(多個(gè)任務(wù)會(huì)自動(dòng)異步執(zhí)行任務(wù),并發(fā))
[queue addOperation:operation1];
// 更為簡(jiǎn)單的寫法? 自動(dòng)異步執(zhí)行任務(wù)闷板,并發(fā)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"operation3? ? ? 下載圖片---%@",[NSThread currentThread]);
}];
設(shè)置最大并發(fā)數(shù)[這可以更好的保證程序的性能]澎灸,即控制并發(fā)執(zhí)行最大線程數(shù)量,以節(jié)省內(nèi)存空間
queue.maxConcurrentOperationCount = 2;
a遮晚、NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序(注意不能相互依賴)性昭;
添加依賴 (和添加到隊(duì)列的先后順序無關(guān))
[operationC addDependency:operationB];
[operationB addDependency:operationA];
b、可以在不同queue中的NSOperation之間創(chuàng)建依賴县遣;
> 線程間通信 回到主線程設(shè)置顯示
> 隊(duì)列的取消糜颠、暫停、恢復(fù)
a萧求、取消隊(duì)列的所有操作
- (void)cancelAllOperations其兴; 【在內(nèi)存警告的時(shí)候可以添加上該方法】
[也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作]
b、暫停和恢復(fù)隊(duì)列
- (void)SetSuspended:(BOOL)b; 【YES表示暫停隊(duì)列饭聚,NO表示恢復(fù)隊(duì)列】
[滾動(dòng)視圖(注意表格視圖也是繼承自UIScrollView的)性能優(yōu)化中可以使用到忌警,開始拖動(dòng)的時(shí)候暫停隊(duì)列下載,拖動(dòng)結(jié)束后恢復(fù)隊(duì)列]
接收到內(nèi)存警告
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// 取消隊(duì)列操作
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
//開始拖動(dòng)秒梳,暫停隊(duì)列操作
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// 結(jié)束拖動(dòng)法绵,恢復(fù)隊(duì)列操作
}
(5) 線程安全(在GCD以后,已經(jīng)幫我們處理了這些問題)
?線程安全問題
實(shí)例:3個(gè)窗口賣票
> 3個(gè)窗口同時(shí)賣票酪碘,即多條線程訪問同一資源;
> 線程哪個(gè)先調(diào)用是不確定的朋譬,先調(diào)度誰是CPU的事;
> 當(dāng)線程任務(wù)執(zhí)行完成兴垦,線程為死亡態(tài)(如果是沒有while循環(huán)徙赢,但第二次點(diǎn)擊的時(shí)候程序就崩潰);
> 多線程的安全隱患
a探越、資源共享(資源搶占):一塊資源可能會(huì)被多個(gè)線程共享(即多個(gè)線程可能訪問一個(gè)資源)狡赐;
(當(dāng)多個(gè)線程訪問同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全的問題)[例如一個(gè)線程取錢钦幔,一個(gè)線程存錢枕屉;例如賣票,多個(gè)窗口賣票即多條線程賣]
> 互斥鎖的使用
a鲤氢、互斥鎖方式一:@synchronized(鎖對(duì)象){//需要加鎖的代碼}
// 鎖定一份代碼只用一把鎖搀擂,用多把鎖是無效的;
b西潘、互斥鎖方式二:
/** 1、互斥鎖的初始化*/
_myLock = [[NSLock alloc] init];
// 2哨颂、加鎖方式2
[_myLock lock];
// 需要加鎖的代碼
// 3喷市、解鎖
[_myLock unlock];
> 互斥鎖的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題;
缺點(diǎn):需要消耗大量CPU資源威恼;
> 互斥鎖使用的前提:多條線程搶占同一資源品姓;
> 單例的線程安全
> 數(shù)據(jù)庫(kù)操作的線程安全
nonatomic(atomic):指定set、get方法是否原子操作箫措。原子操作缭黔,主要指是否線程安全。如果使用atomic那么set蒂破、get方法都是線程安全的--- 當(dāng)一個(gè)線程進(jìn)入get、set方法之后别渔,其他線程無法進(jìn)入該set附迷、get方法,那么久避免多線程并發(fā)破壞數(shù)據(jù)完整性哎媚,atomic是默認(rèn)值喇伯。雖然atomic可以保證對(duì)象數(shù)據(jù)的完整性,但atomic線程安全會(huì)造成性能下降(因?yàn)闀?huì)導(dǎo)致其他線程的阻塞)拨与。因此稻据,大多數(shù)單線程環(huán)境下,都是使用nonatomic來提高set买喧、get方法的訪問性能;
線程注意點(diǎn):
1捻悯、不要同時(shí)開太多線程(1~3條線程即可,不要超過5條);
2淤毛、線程概念:
主線程:UI線程今缚,顯示、刷新UI界面低淡,處理UI控件事件姓言;
子線程:后臺(tái)線程,異步線程蔗蹋;
3何荚、不要把耗時(shí)操作放在主線程,要放在子線程中執(zhí)行猪杭;
19.GCD使用