iOS-多線程(1): 多線程基礎(chǔ)

一嫉晶、基本概念

01 - 進程

  • 進程是指在系統(tǒng)中正在運行的一個應(yīng)用程序大审。
  • 每個進程之間是獨立的贿肩,每個進程均運行在其專用受保護的內(nèi)存空間內(nèi)。
    比如:同時打開迅雷聂使、Xcode,系統(tǒng)就會分別啟動2個進程


    進程(迅雷) -<內(nèi)存>- 進程(Xcode)

    通過『活動監(jiān)視器』可以查看Mac系統(tǒng)中所開啟的進程

02 - 線程

  • 1個進程要想執(zhí)行任務(wù),必須得有線程(每一個進程至少要有1條線程),線程是進程的基本執(zhí)行單元壁拉。
  • 一個進程(程序)的所有任務(wù)都在線程中執(zhí)行
    比如使用酷狗音樂谬俄、使用迅雷下載電影,都需要在線程中執(zhí)行


    進程(線程(任務(wù)
  • 1個線程中任務(wù)的執(zhí)行是串行的
    -如果要在1個線程中執(zhí)行多個任務(wù)弃理,那么只能一個一個地按順序執(zhí)行這些任務(wù)
    -也就是說溃论,在同一時間內(nèi),1個線程只能執(zhí)行1個任務(wù)
    比如在1個線程中下載3個文件(分別是文件A痘昌、文件B钥勋、文件C)


    串行執(zhí)行

03 - 線程和進程的比較

1.線程是CPU調(diào)用(執(zhí)行任務(wù))的最小單位
2.進程是CPU分配資源和調(diào)用的單位
3.一個程序可以對應(yīng)多個進程楞抡,一個進程中可以有多個線程煤裙,但至少要有一個線程。
4.同一個進程內(nèi)的線程共享進程的資源萧恕。


線程和進程的比較

04 - 多線程

  • 1個進程中可以開啟多條線程姑子,每條線程可以并行(同時)執(zhí)行不同的任務(wù)
  • 進程->車間乎婿,線程->車間工人
  • 多線程技術(shù)可以提高程序的執(zhí)行效率
  • 比如同時開啟3條線程分別下載3個文件(分別是文件A、文件B街佑、文件C)


    并行

05 - 多線程并發(fā)執(zhí)行的原理

  • 同一時間谢翎,CPU只能處理1條線程,只有1條線程在工作(執(zhí)行)
  • 多線程并發(fā)(同時)執(zhí)行沐旨,其實是CPU快速地在多條線程之間調(diào)度(切換)
  • 如果CPU調(diào)度線程的時間足夠快森逮,就造成了多線程并發(fā)執(zhí)行的假象
    思考:如果線程非常非常多,會發(fā)生什么情況磁携?
    --CPU會在N多線程之間調(diào)度褒侧,CPU會累死,消耗大量的CPU資源
    --每條線程被調(diào)度執(zhí)行的頻次會降低(線程的執(zhí)行效率降低)


    多線程并發(fā)執(zhí)行的原理

06 - 多線程的優(yōu)谊迄、缺點

優(yōu)點:

  • 能適當(dāng)提高程序的執(zhí)行效率
  • 能適當(dāng)提高資源利用率(CPU闷供、內(nèi)存利用率)

缺點:

  • 創(chuàng)建線程是有開銷的,iOS下主要成本包括:內(nèi)核數(shù)據(jù)結(jié)構(gòu)(大約1kB)、椡撑担空間(子線程512kb歪脏、主線程1MB-(測試512kb),也可以使用-setStackSize:設(shè)置,但必須是4k的倍數(shù)粮呢,而且最小是16k),創(chuàng)建線程大約需要90豪秒的創(chuàng)建時間婿失。
  • 如果開啟大量的線程,會降低程序的性能
  • 線程越多啄寡,CPU在調(diào)度線程上的開銷就越大
  • 程序設(shè)計更加復(fù)雜: 比如線程之間的通信豪硅、多線程的數(shù)據(jù)共享

07 - 多線程在iOS開發(fā)中的應(yīng)用

  • 主線程:
    -- 一個iOS程序運行后,默認會開啟1條線程挺物,稱為『主線程』或『UI線程』
  • 主線程的主要作用
    -- 顯示懒浮、刷新UI界面
    -- 處理UI事件(比如點擊事件、滾動時間识藤、拖拽事件等)
  • 主線程的使用注意
    -- 別將比較耗時的操作放到主線程中
    -- 耗時操作會卡住主線程嵌溢,嚴重影響UI的流暢度眯牧,給用戶一種『卡』的壞體驗
    耗時操作-主線程

    耗時操作-子線程

    08 - iOS中多線程的實現(xiàn)方案
    多線程的實現(xiàn)方案
  • 1.pthread
    說明:pthread的基本使用(需要包含頭文件)
    // 使用pthread創(chuàng)建線程對象
    pthread_t thread;
    NSString name = @"zhengyang";
    // 使用pthread創(chuàng)建線程
    // 第一個參數(shù): 線程對象地址
    // 第二個參數(shù): 線程屬性
    // 第三個參數(shù): 指向函數(shù)的指針
    // 第四個參數(shù): 傳遞給該函數(shù)的參數(shù)
    pthread_create(&thread,NULL,run,(__bridge void
    )(name));
  • 2.NSThread
    (1) NSThread的基本使用
    // 第一種創(chuàng)建線程的方式: alloc init.
    特點: 需要手動開啟線程,可以拿到線程對象進行詳細設(shè)置
    // 創(chuàng)建線程
    /*
    第一個參數(shù): 目標對象
    第二個參數(shù): 選擇器赖草,線程啟動要調(diào)用哪個方法
    第三個參數(shù): 前面方法要接受的參數(shù)(最多只能接受一個參數(shù)学少,沒有則傳nil)
    */
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"zhengyang"];
    // 啟動線程
    [thread start];
  //  第二種創(chuàng)建線程的方式: 分離出一條線程
  //特點: 自動啟動線程。無法對線程進行更詳細的設(shè)置
     /*
         第一個參數(shù):線程啟動調(diào)用的方法
         第二個參數(shù):目標對象
         第三個參數(shù):傳遞給調(diào)用方法的參數(shù)
     */
      [NSThread detachNewThreadSelector(run:) toTarget:self withObject:@"我是分離出來的子線程"];
     // 第三種創(chuàng)建線程的方式:后臺線程
     // 特點:自動啟動線程秧骑,無法進行更詳細設(shè)置
      [self performSelectorInBackground:@selector(run:) withObject:@"我是后臺線程"];
 (2) 設(shè)置線程的屬性
    //  設(shè)置線程的屬性
    //  設(shè)置線程的名稱
     thread.name = @"線程A";
    //  設(shè)置線程的優(yōu)先級版确,注意線程優(yōu)先級的取值范圍為0.0~1.0之間。  
        1.0表示線程的優(yōu)先級最高乎折,如果不設(shè)置該值绒疗,那么理想狀態(tài)下默認為0.5
        thread.threadPriority = 1.0;

(3) 線程的狀態(tài)(了解)
// 線程的各種狀態(tài):新建-就緒-運行-阻塞-死亡
// 常用的控制線程狀態(tài)的方法
[NSTread exit]; //退出當(dāng)前線程
[NSTread sleepForTimeInterval:2.0]; // 阻塞線程
[NSTread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; // 阻塞線程
// 注意: 線程死了不能復(fù)生
(4) 線程安全
01 前期:多個線程訪問同一塊資源會發(fā)生數(shù)據(jù)安全問題
02 解決方案: 加互斥鎖
03 相關(guān)代碼:@synchronized(self){}
04 專業(yè)術(shù)語-線程同步
05 原子和非原子屬性 (是否對setter方法加鎖)
(5) 線程間通信
-(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
// [self download2];

     //    開啟一條子線程來下載圖片
           [NSThread detachNewThreadSelector:@seletor(downloadImage) toTarget:self withObject:nil];
  }
  -(void)downloadImage
  {
    // 1.確定要下載網(wǎng)絡(luò)圖片的url地址,一個url唯一對應(yīng)著網(wǎng)絡(luò)上的一個資源
     NSURL *URL= [NSURL URLWithString:@"http://p6.qhimg.com/t01d2954e2799c461ab.jpg"];
    // 2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進制數(shù)據(jù))
      NSData *data = [NSData dataWithContenesOfURL:rul];
    // 3.把下載到本地的二進制數(shù)據(jù)轉(zhuǎn)換成圖片
      UIImage *image = [UIImage imageWithData:data];
   // 4.回到主線程刷新UI
   // 4.1第一種方式
       [self performSelectorOnMainThread:@selector(showImage:) withObject waitUntilDone:YES];
   // 4.2第二種方式
       [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject waitUntilDone:YES];
   // 4.3第三種方式
       [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUnitilDone:YES];
  }
 (6) 如何計算代碼段的執(zhí)行時間
  // 第一種方式
      NSDate *start = [NSDate date];
      //   根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進制數(shù)據(jù))
      NSData *end = [NSData dataWithContentsOfURL:url];
      NSData *end = [NSDate date];
      NSLog(@"第二步操作花費的時間為%f",[end timeIntervalSinceDate:start]); 
      // 第二種方法
      CFTimeInterval start = CFAbsoluteTimeGetCurrent();
      NSData *data = [NSData dataWithContentsOfURL:url];
      CFTimeInterval end = CFAbsoluteTimeGetCurrent();
      NSLog(@"第二步操作花費的時間為%f,end-start");
  • 3 GCD
    (1) GCD 基本知識
    01 兩個核心概念-隊列和任務(wù)
    02 同步函數(shù)和異步函數(shù)
    (2)GCD基本使用【重點】
    01 異步函數(shù)+并發(fā)隊列: 開啟多條線程骂澄,并發(fā)執(zhí)行任務(wù)
    02 異步函數(shù)+串行隊列:開啟一條線程吓蘑,串行執(zhí)行任務(wù)
    03 同步函數(shù)+并發(fā)隊列:不開線程,串行執(zhí)行任務(wù)
    04 同步函數(shù)+串行隊列:不開線程坟冲,串行執(zhí)行任務(wù)
    05 異步函數(shù)+主隊列: 不開線程磨镶,在主線程中串行執(zhí)行任務(wù)
    06 同步函數(shù)+主隊列:不開線程,串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
    07 注意同步函數(shù)和異步函數(shù)在執(zhí)行順序上面的差異
    (3)GCD 線程間通信
    // 0.獲取一個全局的隊列
    // dispatch_queue_t queue= dispath_get_global_queue(0,0);
     //  1.先開啟一個線程健提,把下載圖片的操作放在子線程中處理
         dispath_async(queue,^{
      // 2.下載圖片
         NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
         NSData *data = [NSData dataWithContentsOfURL:url];
         UIImage *image = [UIImage imageWithData:data];
         NSLog(@"下載操作所在的線程--%@",[NSThread currentThread]); 
      // 3.回到主線程刷新UI
         dispatch_async(dispatch_get_main_queue(),^{
         self.imageView.image = image;
         //  打印查看當(dāng)前線程
         NSLog(@"刷新UI---%@",[NSThread currentThread]);
        });
   }

(4) GCD其它常用函數(shù)
01 柵欄函數(shù)(控制任務(wù)的執(zhí)行順序)
dispatch_barrier_async(queue,^{
NSLog(@"--dispatch_barrier_async-");
});

  02 延遲執(zhí)行
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0 * NSEC_PER_SEC)),
   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)^{
      NSLog(@"---%@",[NSThread currentThread]);
  });
  03 一次性代碼(注意不能放到懶加載)
  - (void)once{
    // 整個程序運行過程中只會執(zhí)行一次
       onceToken用來記錄該部分的代碼是否被執(zhí)行過
       static dispatch_once_t onceToken;
       dispatch_once(&onceToken,^{
        NSLog(@"---");
       })琳猫;
  }
  04 快速迭代(開多個線程并發(fā)完成迭代操作)
     dispatch_apply(subpaths.count,queue,^(size_t index){
     });
  05 隊列組(同柵欄函數(shù))
  //   創(chuàng)建隊列組
    dispatch_group_t group = dispatch_group_create();
   //   隊列組中的任務(wù)執(zhí)行完畢之后私痹,執(zhí)行該函數(shù)
     dispatch_group_notify(dispatch_group_t,dispatch_queue_t queue,dispatch_block_t block);
   06 進入群組和離開群組
    dispatch_group_enter(group); // 執(zhí)行該函數(shù)后脐嫂,后面異步執(zhí)行的block會被group監(jiān)聽
    dispatch_group_leave(group); // 異步block中,所有的任務(wù)都執(zhí)行完畢紊遵,最后離開群組
    // 注意:dispatch_group_enter   dispatch_group_leave必須成對使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末账千,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子暗膜,更是在濱河造成了極大的恐慌匀奏,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桦山,死亡現(xiàn)場離奇詭異,居然都是意外死亡醋旦,警方通過查閱死者的電腦和手機恒水,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饲齐,“玉大人钉凌,你說我怎么就攤上這事∥嫒耍” “怎么了御雕?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵矢沿,是天一觀的道長。 經(jīng)常有香客問我酸纲,道長捣鲸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任闽坡,我火速辦了婚禮栽惶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疾嗅。我一直安慰自己外厂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布代承。 她就那樣靜靜地躺著汁蝶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪论悴。 梳的紋絲不亂的頭發(fā)上掖棉,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音意荤,去河邊找鬼啊片。 笑死,一個胖子當(dāng)著我的面吹牛玖像,可吹牛的內(nèi)容都是我干的紫谷。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼捐寥,長吁一口氣:“原來是場噩夢啊……” “哼笤昨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起握恳,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤瞒窒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乡洼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崇裁,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年束昵,在試婚紗的時候發(fā)現(xiàn)自己被綠了拔稳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡锹雏,死狀恐怖巴比,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤轻绞,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布采记,位于F島的核電站,受9級特大地震影響政勃,放射性物質(zhì)發(fā)生泄漏唧龄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一稼病、第九天 我趴在偏房一處隱蔽的房頂上張望选侨。 院中可真熱鬧,春花似錦然走、人聲如沸援制。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晨仑。三九已至,卻和暖如春拆檬,著一層夾襖步出監(jiān)牢的瞬間洪己,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工竟贯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留答捕,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓屑那,卻偏偏與公主長得像拱镐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子持际,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

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

  • 歡迎大家指出文章中需要改正或者需要補充的地方沃琅,我會及時更新,非常感謝蜘欲。 一. 多線程基礎(chǔ) 1. 進程 進程是指在系...
    xx_cc閱讀 7,198評論 11 70
  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 805評論 0 3
  • 再次回看《狼圖騰》這部電影益眉,讓我對里面的人性以及狼性都有了深刻的了解,甚至還有影視里面的大自然姥份。導(dǎo)演...
    李招琴閱讀 3,350評論 0 1
  • 你有沒有這種情況郭脂,有社交恐懼癥,參加聚會會有尷尬癥澈歉,臉上的笑僵硬的都抽筋了展鸡,有局吃飯時,都認識還好闷祥,...
    Trista趙閱讀 324評論 0 1
  • 相信每一個身在創(chuàng)業(yè)公司的年輕人and中年人都會有一段困惑期凯砍。畢竟不是每一家公司都叫阿里箱硕,每一個老板都叫馬云。在最初...
    殊言成木閱讀 366評論 0 3