iOS_多線程理解

1.基本概念:

什么是進(jìn)程:

1)進(jìn)程是一個(gè)具有獨(dú)立功能的程序關(guān)于某次數(shù)據(jù)集合的一次運(yùn)行活動(dòng)洽胶,他是操作系統(tǒng)分配資源的基本單元.

2) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,就是一段程序執(zhí)行的過程裆馒,我們可以理解為手機(jī)上的一個(gè)app

3)每個(gè)進(jìn)程之間是獨(dú)立的姊氓,每個(gè)進(jìn)程均運(yùn)行在專用且受保護(hù)的內(nèi)存空間內(nèi),擁有獨(dú)立運(yùn)行喷好,所需的全部資源

什么是線程

1)程序執(zhí)行流的最小單元翔横,線程是進(jìn)程中的一個(gè)實(shí)體

2)一個(gè)進(jìn)程要想執(zhí)行任務(wù),必須要至少有一條線程梗搅,應(yīng)用啟動(dòng)的時(shí)候禾唁,系統(tǒng)會默認(rèn)開啟一條線程,也就是主線程无切;

線程和進(jìn)程之間的關(guān)系

1)線程是進(jìn)程的基本執(zhí)行單位荡短,進(jìn)程的所有任務(wù)必須在線程中執(zhí)行(主線程,子線程)

2)線程是cpu分配資源的最小單元哆键,一個(gè)進(jìn)程中所有線程共享進(jìn)程資源

3)一個(gè)進(jìn)程對應(yīng)多個(gè)或者一個(gè)線程掘托,但是必須要有線程

隊(duì)列:這里的隊(duì)列是指執(zhí)行任務(wù)的等待隊(duì)列,即用來存放任務(wù)的隊(duì)列。隊(duì)列是一種特殊的線性表籍嘹,采用FIFO的原則闪盔,即新任務(wù)是被插入到隊(duì)列末尾,讀取總是從頭部開始讀取辱士,讀取一個(gè)釋放一個(gè)

在GCD中有兩種隊(duì)列泪掀,串行和并發(fā),遵循FIFO 區(qū)別在于自行順序不同颂碘,開啟線程數(shù)不同

iOS 中的多線程

NSThread异赫,NSoperationQueue,GCD

我們要明確 NSOperationQueue 與 GCD 之間的關(guān)系

GCD 是面向底層的 C 語言的 API凭涂,NSOpertaionQueue 用 GCD 構(gòu)建封裝的祝辣,是 GCD 的高級抽象。

1切油、GCD 執(zhí)行效率更高蝙斜,而且由于隊(duì)列中執(zhí)行的是由 block 構(gòu)成的任務(wù),這是一個(gè)輕量級的數(shù)據(jù)結(jié)構(gòu)澎胡,寫起 來更方便

2孕荠、GCD 只支持 FIFO 的隊(duì)列娩鹉,而 NSOperationQueue 可以通過設(shè)置最大并發(fā)數(shù),設(shè)置優(yōu)先級稚伍,添加依賴關(guān)系 等調(diào)整執(zhí)行順序

3弯予、NSOperationQueue 甚至可以跨隊(duì)列設(shè)置依賴關(guān)系,但是 GCD 只能通過設(shè)置串行隊(duì)列个曙,或者在隊(duì)列內(nèi)添 加 barrier(dispatch_barrier_async)任務(wù)锈嫩,才能控制執(zhí)行順序,較為復(fù)雜

4、NSOperationQueue 因?yàn)槊嫦驅(qū)ο罂寻幔灾С?KVO呼寸,可以監(jiān)測 operation 是否正在執(zhí)行(isExecuted)、 是否結(jié)束(isFinished)猴贰、是否取消(isCanceld)

? ?實(shí)際項(xiàng)目開發(fā)中对雪,很多時(shí)候只是會用到異步操作,不會有特別復(fù)雜的線程關(guān)系管理米绕,所以蘋果推崇的 且優(yōu)化完善瑟捣、運(yùn)行快速的?GCD?是首選

? ?如果考慮異步操作之間的事務(wù)性,順序行栅干,依賴關(guān)系迈套,比如多線程并發(fā)下載,GCD需要自己寫更多的 代碼來實(shí)現(xiàn)非驮,而?NSOperationQueue?已經(jīng)內(nèi)建了這些支持

? ?不論是GCD還是NSOperationQueue交汤,我們接觸的都是任務(wù)和隊(duì)列,都沒有直接接觸到線程劫笙,事實(shí)上 線程管理也的確不需要我們操心芙扎,系統(tǒng)對于線程的創(chuàng)建,調(diào)度管理和釋放都做得很好填大。而?NSThread?需要我們自己去管理線程的生命周期戒洼,還要考慮線程同步、加鎖問題允华,造成一些性能上的開銷


2圈浇、performSelector

dispatch_async(dispatch_get_global_queue(0, 0), ^{

? ? ? ? [self performSelector:@selector(threadFucntion) withObject:nil afterDelay:0];

? ? });

這里的 threadFucntion 方法是不會去執(zhí)行的,原因在于

這個(gè)方法要?jiǎng)?chuàng)建提交任務(wù)到 runloop 上的靴寂,而 gcd 底層創(chuàng)建的線程是默認(rèn)沒有開啟對應(yīng) runloop 的磷蜀,所有 這個(gè)方法就會失效。

而如果將 dispatch_get_global_queue 改成主隊(duì)列百炬,由于主隊(duì)列所在的主線程是默認(rèn)開啟了 runloop 的褐隆, 就會去執(zhí)行(將 dispatch_async 改成同步,因?yàn)橥绞窃诋?dāng)前線程執(zhí)行剖踊,那么如果當(dāng)前線程是主線程庶弃,test 方法也是會去執(zhí)行的)衫贬。

1、問:怎么用 GCD 實(shí)現(xiàn)多讀單寫?

多讀單寫的意思就是:可以多個(gè)讀者同時(shí)讀取數(shù)據(jù)歇攻,而在讀的時(shí)候固惯,不能去寫入數(shù)據(jù)。并且缴守,在寫的過程 中葬毫,不能有其他寫者去寫。即讀者之間是并發(fā)的屡穗,寫者與讀者或其他寫者是互斥的供常。

這里的寫處理就是通過柵欄的形式去寫。 就可以用?dispatch_barrier_sync(柵欄函數(shù))去實(shí)現(xiàn)

多讀單寫實(shí)現(xiàn)方式:

-(id)readDataForKey:(NSString*)key{

? ? __blockidresult;


? ? //當(dāng)前線程和取的線程為同一個(gè)

? ? dispatch_queue_t concurrent = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);


? ? dispatch_sync(concurrent, ^{

? ? ? ? result = [selfvalueForKey:key];

? ? });

? ? returnresult;

}

-(void)writeDataForKey:(NSString*)key{


? ? dispatch_queue_t concurretn = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);


? ? dispatch_barrier_async(concurretn, ^{

? ? ? ? [selfsetValue:@"data"forKey:key];

? ? });

}

介紹:dispatch_group_async

場景:在 n 個(gè)耗時(shí)并發(fā)任務(wù)都完成后鸡捐,再去執(zhí)行接下來的任務(wù)。比如麻裁,在 n 個(gè)網(wǎng)絡(luò)請求完成后去刷新 UI 頁 面箍镜。

dispatch_queue_t concurrentQueen = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

? ? dispatch_group_t group = dispatch_group_create();

? ? for(NSIntegeri =0; i <5; i ++ ) {

? ? ? ? dispatch_group_async(group, concurret, ^{

? ? ? ? ? ? sleep(1);

? ? ? ? ? ? NSLog(@"網(wǎng)絡(luò)請求 %ld",i);

? ? ? ? });

? ? }

? ? dispatch_group_notify(group,concurrentQueen, ^{

? ? ? ? NSLog(@"刷新頁面");

? ? });

介紹:Dispatch Semaphore

GCD?中的信號量是指?Dispatch Semaphore,是持有計(jì)數(shù)的信號煎源。

A 常用做色迂,保持線程同步,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行

B 保持線程安全手销,為線程加鎖

__blockNSIntegernumber =0;

? ? dispatch_semaphore_t semphone = dispatch_semaphore_create(0);

? ? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

? ? ? ? number =100;

? ? ? ? sleep(10);

? ? ? ? dispatch_semaphore_signal(semphone);

? ? });

? ? dispatch_semaphore_wait(semphone, DISPATCH_TIME_FOREVER);


? ? NSLog(@"321321aaaaaaa13231? %ld",number);

發(fā)現(xiàn) 過了10秒鐘才打印number = 10 歇僧;

說明阻塞了當(dāng)前線程,將異步執(zhí)行锋拖,轉(zhuǎn)換為同步了

在線程安全中可以將 dispatch_semaphore_wait 看作加鎖诈悍,而 dispatch_semaphore_signal 看作解鎖 首先創(chuàng)建全局變量

@property (nonatomic,strong)dispatch_semaphore_t semphore;

//為線程加鎖

-(void)semPhoreLock{

? ? dispatch_semaphore_wait(_semphore, DISPATCH_TIME_FOREVER);

? ? _count++ ;

? ? sleep(1);

? ? NSLog(@"sdad? d3232 %d",_count);

? ? dispatch_semaphore_signal(_semphore);

}

-(void)asyncDic{

? ? _semphore = dispatch_semaphore_create(1);

? ? for(inti =0; i <100; i ++ ) {

? ? ? ? dispatch_async(dispatch_get_global_queue(0, 0), ^{

? ? ? ? ? ? [selfsemPhoreLock];

? ? ? ? });

? ? }

}

觀察到打印是從1打印100,且dispatch_semaphore_t必須用strong修飾

原因如下:

在子線程中并發(fā)執(zhí)行?asyncTask兽埃,那么第一個(gè)添加到并發(fā)隊(duì)列里的侥钳,會將信號量減?1,此時(shí)信號量等于?0柄错, 可以執(zhí)行接下來的任務(wù)舷夺。而并發(fā)隊(duì)列中其他任務(wù),由于此時(shí)信號量不等于?0售貌,必須等當(dāng)前正在執(zhí)行的任務(wù) 執(zhí)行完畢后調(diào)用?dispatch_semaphore_signal?將信號量加?1给猾,才可以繼續(xù)執(zhí)行接下來的任務(wù),以此類推颂跨,從而 達(dá)到線程加鎖的目的敢伸。

延時(shí)函數(shù)

dispatch_after?

dispatch_after 能讓我們添加進(jìn)隊(duì)列的任務(wù)延時(shí)執(zhí)行,該函數(shù)并不是在指定時(shí)間后執(zhí)行處理毫捣,而只是在指 定時(shí)間追加處理到 dispatch_queue

dispatch_once_tonce 實(shí)現(xiàn)單例

-(instancetype)shareInstance{

? ? static?dispatch_once_tonceToken;

? ? static?id?instance =nil;

? ? dispatch_once(&onceToken, ^{

? ? ? ? instance = [[self?alloc]init];

? ? });

? ? return?instance;

}

NSThread+runloop 實(shí)現(xiàn)常駐線程


[self performSelector:@selector(threadJJJ) onThread:[ViewController shareThread] withObject:nil waitUntilDone:NO];

調(diào)用performselector 這個(gè)就實(shí)現(xiàn)了打印详拙,說明帝际,實(shí)現(xiàn)NSThread + RunRoop 實(shí)現(xiàn)成功了

自旋鎖:是一種用于保護(hù)多線程共享資源的鎖,與一般互斥鎖(mutex)不同之處在于當(dāng)自旋鎖嘗試獲取鎖時(shí)以忙等 待(busy waiting)的形式不斷地循環(huán)檢查鎖是否可用饶辙。當(dāng)上一個(gè)線程的任務(wù)沒有執(zhí)行完畢的時(shí)候(被鎖住)蹲诀, 那么下一個(gè)線程會一直等待(不會睡眠),當(dāng)上一個(gè)線程的任務(wù)執(zhí)行完畢弃揽,下一個(gè)線程會立即執(zhí)行脯爪。在多 CPU?的環(huán)境中,對持有鎖較短的程序來說矿微,使用自旋鎖代替一般的互斥鎖往往能夠提高程序的性能痕慢。

互斥鎖:當(dāng)上一個(gè)線程的任務(wù)沒有執(zhí)行完畢的時(shí)候(被鎖住),那么下一個(gè)線程會進(jìn)入睡眠狀態(tài)等待任務(wù)執(zhí)行完畢涌矢, 當(dāng)上一個(gè)線程的任務(wù)執(zhí)行完畢掖举,下一個(gè)線程會自動(dòng)喚醒然后執(zhí)行任務(wù)。

自旋鎖會忙等:?所謂忙等娜庇,即在訪問被鎖資源時(shí)塔次,調(diào)用者線程不會休眠,而是不停循環(huán)在那里名秀,直到被鎖 資源釋放鎖励负。互斥鎖會休眠:?所謂休眠匕得,即在訪問被鎖資源時(shí)继榆,調(diào)用者線程會休眠,此時(shí)?cpu?可以調(diào)度其他線程工 作汁掠。直到被鎖資源釋放鎖略吨。此時(shí)會喚醒休眠線程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末调塌,一起剝皮案震驚了整個(gè)濱河市晋南,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羔砾,老刑警劉巖负间,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姜凄,居然都是意外死亡政溃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門态秧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來董虱,“玉大人,你說我怎么就攤上這事》哂眨” “怎么了云头?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淫半。 經(jīng)常有香客問我溃槐,道長,這世上最難降的妖魔是什么科吭? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任昏滴,我火速辦了婚禮,結(jié)果婚禮上对人,老公的妹妹穿的比我還像新娘谣殊。我一直安慰自己,他們只是感情好牺弄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布姻几。 她就那樣靜靜地躺著,像睡著了一般势告。 火紅的嫁衣襯著肌膚如雪鲜棠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天培慌,我揣著相機(jī)與錄音,去河邊找鬼柑爸。 笑死吵护,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的表鳍。 我是一名探鬼主播馅而,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼譬圣!你這毒婦竟也來了瓮恭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤厘熟,失蹤者是張志新(化名)和其女友劉穎屯蹦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绳姨,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡登澜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了飘庄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脑蠕。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谴仙,到底是詐尸還是另有隱情迂求,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布晃跺,位于F島的核電站揩局,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏哼审。R本人自食惡果不足惜谐腰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涩盾。 院中可真熱鬧十气,春花似錦、人聲如沸春霍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽址儒。三九已至芹枷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間莲趣,已是汗流浹背鸳慈。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喧伞,地道東北人走芋。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像潘鲫,于是被迫代替她去往敵國和親翁逞。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 戀愛中哪個(gè)付出的多溉仑,很難去理性的衡量出百分比挖函,不過普遍的意義上是女生結(jié)婚后會更加顧家一些。 最近新聞上熱度很高的牛...
    幸福傳遞者閱讀 160評論 1 1
  • 2017年12月12日星期二天氣:晴 今天出奇的冷浊竟,下午下班接上兒子去錄音怨喘,本計(jì)劃1個(gè)小時(shí)可以結(jié)束,可是錄制一直持...
    唐麗娟閱讀 259評論 0 1
  • 2.0(6/17-6/24)周檢視2018.6.24 90天的第83天 上周重點(diǎn)突破目標(biāo)是: 健身(58kg)未完...
    戴戴005閱讀 140評論 0 0
  • 她家本不優(yōu)裕振定,靠父親替米行做工勉強(qiáng)過活哲思。但一家和美,雖苦也樂吩案。 那日花朝節(jié)傍晚棚赔,她偷偷溜去花燈會的布置現(xiàn)場,她從來...
    夢里有條魚閱讀 482評論 1 3