首先我們先來(lái)談一下進(jìn)程和線程的概念
進(jìn)程:? 實(shí)際上進(jìn)程就是我們電腦或者手機(jī)上運(yùn)行的應(yīng)用
線程:? 是進(jìn)程最小的執(zhí)行單元 ---- 應(yīng)用程序里面必須要做一些事情(就是我們的寫(xiě)的代碼)- 就在線程里去執(zhí)行
所以,進(jìn)程必須要有至少一個(gè)線程, 在我們應(yīng)用程序啟動(dòng)的時(shí)候, 系統(tǒng)會(huì)自動(dòng)幫我們開(kāi)啟一條線程, 這個(gè)就是`主線程`, 在我們移動(dòng)端主線程又叫`UI線程
CPU調(diào)度線程的原理:? CPU 是在多個(gè)線程中非称崤快速的來(lái)回切換, 給我們的感覺(jué)就是`同一時(shí)間`在執(zhí)行多個(gè)事情(線程)
CPU 調(diào)度線程時(shí)需要注意: CPU調(diào)度線程的不確定性 (我們程序無(wú)法控制的)
為什么要用多線程:
1. 用多線程的核心是為了解決 耗時(shí)操作阻塞用戶交互
2. 提升代碼執(zhí)行效率 (所有的東西都是有代價(jià), 線程并不是越多越好)
線程的狀態(tài): 創(chuàng)建, 就緒, 執(zhí)行, 阻塞, 死亡
----------------------------------------------------------------
原子屬性
@synchronized? 是加互斥鎖
atomic? 實(shí)際上系統(tǒng)會(huì)在setter 方法中加鎖---自旋鎖? (為什么getter 方法中不加鎖)
自旋鎖的效率要比互斥鎖高.
UIkit 不是線程安全? (怎么保證控件顯示的數(shù)據(jù)是正確的?)
同步和異步的概念
同步: 代碼一行一行的往下依次執(zhí)行,? (/**在同一個(gè)線程中的代碼都是一行一行依次往下執(zhí)行的*/)
異步: 異步實(shí)際上相當(dāng)于多線程的代名詞,? 就是把對(duì)應(yīng)的代碼放到其他線程執(zhí)行, 當(dāng)前線程不需要等待其他線程的代碼執(zhí)行完成才往下走, 而是直接執(zhí)行后面的代碼.
需要注意的重點(diǎn): 當(dāng)前線程不代表主線程, 當(dāng)前代碼在哪個(gè)線程中調(diào)用, 那當(dāng)前線程就代碼哪個(gè)線程
注意: 所有網(wǎng)絡(luò)操作都是耗時(shí)的.
需要特別注意的是: 不能在子線程中去做更新UI的操作,? 所有對(duì)UI的操作都必須要放到主線程中 (為什么主線程叫UI線程, 就是因?yàn)檫@個(gè)).
線程間的通信:? 就是在多個(gè)線程之間傳遞數(shù)據(jù),? 在子線程中要調(diào)用UI線程 可以用:
[self performSelectorOnMainThread:@selector(updateImageView) withObject:nil waitUntilDone:NO]
GCD -- 大中央調(diào)度
GCD 的兩大核心概念: 隊(duì)列 和 任務(wù)
隊(duì)列: 調(diào)度任務(wù).
任務(wù): 就是我們寫(xiě)的代碼, 要執(zhí)行的事情
GCD 就是使用下面兩個(gè)c的方法去使用
dispatch_async? 開(kāi)啟子線程, 異步執(zhí)行代碼
dispatch_sync? 不會(huì)開(kāi)啟子線程, 在當(dāng)前線程去執(zhí)行代碼
這兩個(gè)函數(shù)的作用,
1. 就是把任務(wù)放到隊(duì)列中去執(zhí)行.
2. 是否開(kāi)啟新的線程
隊(duì)列
串行隊(duì)列特點(diǎn): 如果要開(kāi)啟線程,只會(huì)開(kāi)啟一條線程
并發(fā)隊(duì)列特點(diǎn): 可以開(kāi)啟多條線程
總結(jié):
1. 開(kāi)不開(kāi)線程是由執(zhí)行函數(shù)決定的. dispatch_async 會(huì)開(kāi)啟線程在子線程中執(zhí)行函數(shù), dispatch_sync不會(huì)開(kāi)啟線程在當(dāng)前線程中去執(zhí)行任務(wù)
2. 串行隊(duì)列只會(huì)開(kāi)啟一條線程
以先進(jìn)先出(FIFO)的方式,順序調(diào)度隊(duì)列中的任務(wù)執(zhí)行
**無(wú)論隊(duì)列中所指定的執(zhí)行任務(wù)函數(shù)是同步還是異步泽示,都會(huì)等待前一個(gè)任務(wù)執(zhí)行完成后钩骇,再調(diào)度后面的任務(wù)
3. 并發(fā)隊(duì)列? 會(huì)開(kāi)啟多條線程, 如果開(kāi)啟了多條線程,任務(wù)執(zhí)行起來(lái)的順序就是不確定的.
如果用的是同步執(zhí)行函數(shù)dispatch_sync, 即使用并發(fā)隊(duì)列也不會(huì)開(kāi)啟線程, 只會(huì)在當(dāng)前線程依次執(zhí)行任務(wù)
以先進(jìn)先出的方式,并發(fā)調(diào)度隊(duì)列中的任務(wù)執(zhí)行
**如果當(dāng)前調(diào)度的任務(wù)是同步執(zhí)行的郑象,會(huì)等待任務(wù)執(zhí)行完成后贡这,再調(diào)度后續(xù)的任務(wù)
**如果當(dāng)前調(diào)度的任務(wù)是異步執(zhí)行的,同時(shí)底層線程池有可用的線程資源厂榛,會(huì)再新的線程調(diào)度后續(xù)任務(wù)的執(zhí)行
不需要等待前一個(gè)任務(wù)執(zhí)行完成.
4.全局隊(duì)列:? 全局隊(duì)列的特性和并發(fā)隊(duì)列是一樣的, 只是它是有系統(tǒng)創(chuàng)建, 給我們提供的一個(gè)統(tǒng)一的隊(duì)列, 方便我們開(kāi)發(fā)使用
5.主隊(duì)列: **在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
**如果當(dāng)前主線程正在有任務(wù)執(zhí)行盖矫,那么無(wú)論主隊(duì)列中當(dāng)前被添加了什么任務(wù)丽惭,都不會(huì)被調(diào)度
**dispatch_async 如果執(zhí)行隊(duì)列是主隊(duì)列, 這個(gè)執(zhí)行函數(shù)不會(huì)開(kāi)啟新的線程
需要注意的事項(xiàng):? 死鎖---
在主線程中調(diào)用同步的執(zhí)行函數(shù), 并且執(zhí)行的隊(duì)列寫(xiě)的是主隊(duì)列, 就會(huì)產(chǎn)生死鎖
所以千萬(wàn)不要在主線程中寫(xiě)下面的代碼
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"main queue --%@",[NSThread currentThread]);
});