多線程(2)——NSThread

iOS中實(shí)現(xiàn)多線程的四種方案

  • pthread
  • NSThread
  • GCD
  • NSOpreation

Pthread:這種純c語(yǔ)言的就別用了吧蜻直,還要自己管理線程的生命周期,果斷不用
NSThread:這個(gè)雖然自己管理線程的生命周期基括,但這是面向?qū)ο蟮模琌C語(yǔ)言归园,不常用到但要會(huì)用
GCD:這個(gè)很重要、很重要、很重要 自動(dòng)管理線程的生命周期 使用率非常非常頻繁
NSOpreation:這個(gè)也很重要白热,必須掌握佑稠,沒(méi)什么好說(shuō)的,也是自動(dòng)管理線程的生命周期猾编,使用率也非常高

簡(jiǎn)單了解下Pthread

只要create一次就會(huì)創(chuàng)建一個(gè)新的線程
系統(tǒng)會(huì)自動(dòng)在子線程中調(diào)用傳入的函數(shù)

  /*
第一個(gè)參數(shù): 線程的代號(hào)(當(dāng)做就是線程)
第二個(gè)參數(shù): 線程的屬性
第三個(gè)參數(shù): 指向函數(shù)的指針, 就是將來(lái)線程需要執(zhí)行的方法
第四個(gè)參數(shù): 給第三個(gè)參數(shù)的指向函數(shù)的指針 傳遞的參數(shù)
一般情況下C語(yǔ)言中的類型都是以 _t或者Ref結(jié)尾
  */
pthread_t threadId;
// 只要create一次就會(huì)創(chuàng)建一個(gè)新的線程
pthread_create(&threadId , NULL, &demo, "hq");

關(guān)于NSThread

  • NSThread對(duì)比后面兩種是相對(duì)輕量級(jí)的瘤睹,更直觀地控制線程對(duì)象
  • 但需要自己管理線程的生命周期、同步答倡、加鎖問(wèn)題轰传,在性能上會(huì)有一定的消耗
  • 注意:一個(gè)NSThread對(duì)象就代表一條線程

創(chuàng)建方法

** 第一種方法 ** (手動(dòng)開(kāi)啟線程)

// 線程一啟動(dòng),就會(huì)在線程thread中執(zhí)行self的run方法

// 1.創(chuàng)建線程
NSThread *thread = [[NSThread alloc] initWithTarget:selfselector:@selector(run) object:nil];

// 2.設(shè)置線程的優(yōu)先級(jí)(0.0 - 1.0瘪撇,1.0最高級(jí))  
thread.threadPriority = 1; 

// 3.啟動(dòng)線程
[thread start];

** 第二種方法 ** (自動(dòng)開(kāi)啟線程)

// detachNewThreadSelector: 不用手動(dòng)調(diào)用start方法, 系統(tǒng)會(huì)自動(dòng)啟動(dòng) 沒(méi)有返回值, 不能對(duì)線程進(jìn)行更多的設(shè)置

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

** 第三種方法 ** (隱式創(chuàng)建并啟動(dòng)線程)

// 系統(tǒng)就會(huì)自動(dòng)創(chuàng)建一個(gè)子線程, 并且在子線程中自動(dòng)執(zhí)行self的@selector方法

[self performSelectorInBackground:@selector(run) withObject:nil];

NSThread用法

  • 主線程相關(guān)用法
 + (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
+ (BOOL)isMainThread; // 是否為主線程
NSThread *main = [NSThread mainThread];
  • 獲得當(dāng)前線程
NSThread *current = [NSThread currentThread];
  • 獲取線程的名字

    - (void)setName:(NSString *)name;
    - (NSString *)name;
    

線程的狀態(tài)

  • 創(chuàng)建出來(lái) -> 新建狀態(tài)
  • 調(diào)用start -> 準(zhǔn)備就緒
  • 被CPU調(diào)用 -> 運(yùn)行
  • sleep -> 阻塞
  • 執(zhí)行完畢, 或者被強(qiáng)制關(guān)閉 -> 死亡
啟動(dòng)線程
- (void)start; 
// 進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)获茬。當(dāng)線程任務(wù)執(zhí)行完畢,自動(dòng)進(jìn)入死亡狀態(tài)

阻塞(暫停)線程
// sleep方法是一個(gè)類方法, 所以說(shuō)明在哪個(gè)線程中調(diào)用, 就會(huì)給哪個(gè)線程設(shè)置暫時(shí)
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)time;

// 暫停1s  
[NSThread sleepForTimeInterval:1]; 
[NSThread sleepUntilDate:[NSDate dateWithTimeInterval:1 sinceDate:[NSDate date]]];
強(qiáng)制停止線程
// 進(jìn)入死亡狀態(tài)
+ (void)exit;
注意:一旦線程停止(死亡)了倔既,就不能再次開(kāi)啟任務(wù)

多線程的安全隱患及解決措施

  • 資源共享
    • 一塊資源可能會(huì)被多個(gè)線程共享恕曲,也就是多個(gè)線程可能會(huì)訪問(wèn)同一塊資源,比如多個(gè)線程訪問(wèn)同一個(gè)對(duì)象渤涌、同一個(gè)變量佩谣、同一個(gè)文件等
    • 當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題
  • 解決措施
    • 互斥鎖
    • 互斥鎖的使用前提:多條線程搶奪同一塊資源
    • 注意:鎖定1份代碼只用1把鎖实蓬,用多把鎖是無(wú)效的
  • 使用格式
// (鎖對(duì)象self)
@synchronized
{ 
    // 需要鎖定的代碼      
}
        /*
         只要被@synchronized的{}包裹起來(lái)的代碼, 同一時(shí)刻就只能被一個(gè)線程執(zhí)行
         注意:
         1. 只要枷鎖就會(huì)消耗性能
         2. 加鎖必須傳遞一個(gè)對(duì)象, 作為鎖
         3. 如果想真正的鎖住代碼, 那么多個(gè)線程必須使用同一把鎖才行
         4. 加鎖的時(shí)候盡量縮小范圍, 因?yàn)榉秶酱笮阅芫驮降?         */
  • 互斥鎖的優(yōu)缺點(diǎn)

    • 優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問(wèn)題
    • 缺點(diǎn):需要消耗大量的CPU資源
  • 線程同步

    • 線程同步的意思是:多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù))
      互斥鎖茸俭,就是使用了線程同步技術(shù)

原子和非原子屬性

  • OC在定義屬性時(shí)有nonatomic和atomic兩種選擇
    • atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)
    • nonatomic:非原子屬性安皱,不會(huì)為setter方法加鎖
  • 原子和非原子屬性的選擇
    • atomic:線程安全调鬓,需要消耗大量的資源
    • nonatomic:非線程安全,適合內(nèi)存小的移動(dòng)設(shè)備
  • iOS開(kāi)發(fā)的建議
    • 所有屬性都聲明為nonatomic
    • 盡量避免多線程搶奪同一塊資源
    • 盡量將加鎖练俐、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器端處理袖迎,減小移動(dòng)客戶端的壓力

注意點(diǎn): atomic系統(tǒng)自動(dòng)給我們添加的鎖不是互斥鎖/ 自旋鎖

  • 自旋鎖和互斥鎖對(duì)比
    • 相同點(diǎn):都能夠保證多線程在同一時(shí)候, 只能有一個(gè)線程操作鎖定的代碼
    • 不同點(diǎn)
      • 如果是互斥鎖, 假如現(xiàn)在被鎖住了, 那么后面來(lái)得線程就會(huì)進(jìn)入”休眠”狀態(tài), 直到解鎖之后, 又會(huì)喚醒線程繼續(xù)執(zhí)行
      • 如果是自旋鎖, 假如現(xiàn)在被鎖住了, 那么后面來(lái)得線程不會(huì)進(jìn)入休眠狀態(tài), 會(huì)一直傻傻的等待, 直到解鎖之后立刻執(zhí)行
      • 自旋鎖更適合做一些較短的操作

線程間的通信

  • 什么叫做線程間通信

    • 在1個(gè)進(jìn)程中,線程往往不是孤立存在的腺晾,多個(gè)線程之間需要經(jīng)常進(jìn)行通信
    • 比如在主線程添加imageView燕锥,在子線程中下載圖片,然后又回到主線程中顯示圖片
    • 注意點(diǎn): 更新UI一定要在主線程中更新
  • 線程間通信的體現(xiàn)

    • 1個(gè)線程傳遞數(shù)據(jù)給另1個(gè)線程
    • 在1個(gè)線程中執(zhí)行完特定任務(wù)后悯蝉,轉(zhuǎn)到另1個(gè)線程繼續(xù)執(zhí)行任務(wù)
  • 在當(dāng)前線程

[self performSelector:@selector(run) withObject:nil]; 
  • 在主線程

    [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
    
  • 在指定線程

[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];  

// waitUntilDone的含義: 如果傳入的是YES: 那么會(huì)等到主線程中的方法執(zhí)行完畢, 才會(huì)繼續(xù)執(zhí)行下面其他行的代碼 如果傳入的是NO: 那么不用等到主線程中的方法執(zhí)行完畢, 就可以繼續(xù)執(zhí)行下面其它行的代碼

線程間的通信最常見(jiàn)的就是在子線程中做耗時(shí)操作归形,然后回到主線程刷新UI

關(guān)于NSThread的總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鼻由,隨后出現(xiàn)的幾起案子暇榴,更是在濱河造成了極大的恐慌厚棵,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔼紧,死亡現(xiàn)場(chǎng)離奇詭異婆硬,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)奸例,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門彬犯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人查吊,你說(shuō)我怎么就攤上這事谐区。” “怎么了逻卖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵宋列,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我评也,道長(zhǎng)炼杖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任仇参,我火速辦了婚禮嘹叫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诈乒。我一直安慰自己,他們只是感情好婆芦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布怕磨。 她就那樣靜靜地躺著,像睡著了一般消约。 火紅的嫁衣襯著肌膚如雪肠鲫。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天或粮,我揣著相機(jī)與錄音导饲,去河邊找鬼。 笑死氯材,一個(gè)胖子當(dāng)著我的面吹牛渣锦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氢哮,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼袋毙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了冗尤?” 一聲冷哼從身側(cè)響起听盖,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胀溺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后皆看,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仓坞,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年腰吟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扯躺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝎困,死狀恐怖录语,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情禾乘,我是刑警寧澤澎埠,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站始藕,受9級(jí)特大地震影響蒲稳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伍派,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一江耀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诉植,春花似錦祥国、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至灼擂,卻和暖如春壁查,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剔应。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工睡腿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峻贮。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓席怪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親月洛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子何恶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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

  • 一、多線程基礎(chǔ) 基本概念 進(jìn)程進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序每個(gè)進(jìn)程之間是獨(dú)立的嚼黔,每個(gè)進(jìn)程均運(yùn)行在其專用且...
    AlanGe閱讀 543評(píng)論 0 0
  • 多線程基本概念 單核CPU细层,同一時(shí)間cpu只能處理1個(gè)線程,只有1個(gè)線程在執(zhí)行 惜辑。多線程同時(shí)執(zhí)行:是CPU快速的在...
    WeiHing閱讀 702評(píng)論 1 5
  • 線程概述 有些程序是一條直線,起點(diǎn)到終點(diǎn)疫赎;有些程序是一個(gè)圓盛撑,不斷循環(huán),直到將它切斷一個(gè)運(yùn)行著的程序就是一個(gè)進(jìn)程或者...
    褪而未變閱讀 296評(píng)論 0 0
  • 希望有一天你難過(guò)了捧搞,會(huì)第一個(gè)想起我的名字抵卫。
    436522a73fa0閱讀 216評(píng)論 0 1
  • 一介粘、初相識(shí) 我和曉玥認(rèn)識(shí)的時(shí)候是在高一軍訓(xùn)的時(shí)候。我記得那時(shí)候是夏天吧晚树,大家都穿著軍訓(xùn)服在訓(xùn)練場(chǎng)上跑步姻采。因?yàn)槲易约?..
    我是影子啊閱讀 560評(píng)論 5 5