愛上多線程 之 GCD

01 進程
    進程是指在系統(tǒng)中正在運行的一個應(yīng)用程序。每個進程之間是獨立的驰唬,每個進程均運行在其專用且受保護的內(nèi)存空間內(nèi)顶岸。
02 線程
    2-1 基本概念
        1個進程要想執(zhí)行任務(wù),必須得有線程(每1個進程至少要有1條線程)叫编,線程是進程的基本執(zhí)行單元辖佣,一個進程(程序)的所有任務(wù)都在線程中執(zhí)行。
    2-2 線程的串行
        1個線程中任務(wù)的執(zhí)行是串行的搓逾,如果要在1個線程中執(zhí)行多個任務(wù)卷谈,那么只能一個一個地按順序執(zhí)行這些任務(wù)。也就是說霞篡,在同一時間內(nèi)世蔗,1個線程只能執(zhí)行1個任務(wù)端逼。
03 多線程
    3-1 基本概念
        即1個進程中可以開啟多條線程,每條線程可以并行(同時)執(zhí)行不同的任務(wù)污淋。
    3-2 線程的并行
        并行即同時執(zhí)行顶滩。比如同時開啟3條線程分別下載3個文件(分別是文件A、文件B寸爆、文件C礁鲁。
    3-3 多線程并發(fā)執(zhí)行的原理
        在同一時間里,CPU只能處理1條線程而昨,只有1條線程在工作(執(zhí)行)救氯。多線程并發(fā)(同時)執(zhí)行,其實是CPU快速地在多條線程之間調(diào)度(切換)歌憨,如果CPU調(diào)度線程的時間足夠快着憨,就造成了多線程并發(fā)執(zhí)行的假象
    3-4 多線程優(yōu)缺點
        優(yōu)點
            1)能適當提高程序的執(zhí)行效率。
            2)能適當提高資源利用率(CPU务嫡、內(nèi)存利用率)
        缺點
            1)開啟線程需要占用一定的內(nèi)存空間(默認情況下甲抖,主線程占用1M,子線程占用512KB)心铃,如果開啟大量的線程准谚,會占用大量的內(nèi)存空間,降低程序的性能去扣。
            2)線程越多柱衔,CPU在調(diào)度線程上的開銷就越大。
            3)程序設(shè)計更加復(fù)雜:比如線程之間的通信愉棱、多線程的數(shù)據(jù)共享
--------------------------
04 多線程在iOS開發(fā)中的應(yīng)用
    4-1 主線程
        1)一個iOS程序運行后唆铐,默認會開啟1條線程,稱為“主線程”或“UI線程”奔滑。
        2)作用艾岂。刷新顯示UI,處理UI事件。
    4-2 使用注意
        1)不要將耗時操作放到主線程中去處理朋其,會卡住線程王浴。
        2)和UI相關(guān)的刷新操作必須放到主線程中進行處理。
--------------------------
05 iOS中多線程的實現(xiàn)方案
    5-1 pthread
        a.特點:
          1)一套通用的多線程API
          2)適用于Unix\Linux\Windows等系統(tǒng)
          3)跨平臺\可移植
          4)使用難度大
        b.使用語言:c語言
        c.使用頻率:幾乎不用
        d.線程生命周期:由程序員進行管理

    5-2 NSThread
        a.特點:
            1)使用更加面向?qū)ο?            2)簡單易用梅猿,可直接操作線程對象
        b.使用語言:OC語言
        c.使用頻率:偶爾使用
        d.線程生命周期:由程序員進行管理

    5-3 GCD
        a.特點:
            1)旨在替代NSThread等線程技術(shù)
            2)充分利用設(shè)備的多核(自動)
        b.使用語言:C語言
        c.使用頻率:經(jīng)常使用
        d.線程生命周期:自動管理

    5-4 NSOperation
        a.特點:
            1)基于GCD(底層是GCD)
            2)比GCD多了一些更簡單實用的功能
            3)使用更加面向?qū)ο?        b.使用語言:OC語言
        c.使用頻率:經(jīng)常使用
        d.線程生命周期:自動管理

2 pthread

說明:pthread的基本使用(需要包含頭文件)
    //使用pthread創(chuàng)建線程對象
    pthread_t thread;
    NSString *name = @"wendingding";
    //使用pthread創(chuàng)建線程
    //第一個參數(shù):線程對象地址
    //第二個參數(shù):線程屬性
    //第三個參數(shù):指向函數(shù)的執(zhí)行
    //第四個參數(shù):傳遞給該函數(shù)的參數(shù)
    pthread_create(&thread, NULL, run, (__bridge void *)(name));

3 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:@"wendingding"];
     //啟動線程
    [thread start];

//第二種創(chuàng)建線程的方式:分離出一條子線程
//特點:自動啟動線程筛婉,無法對線程進行更詳細的設(shè)置
    /*
     第一個參數(shù):線程啟動調(diào)用的方法
     第二個參數(shù):目標對象
     第三個參數(shù):傳遞給調(diào)用方法的參數(shù)
     */
    [NSThread detachNewThreadSelector:@selector(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)的方法
[NSThread exit];//退出當前線程
[NSThread sleepForTimeInterval:2.0];//阻塞線程
[NSThread 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:@selector(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 dataWithContentsOfURL:url];

    //3.把下載到本地的二進制數(shù)據(jù)轉(zhuǎn)換成圖片
    UIImage *image = [UIImage imageWithData:data];

    //4.回到主線程刷新UI
    //4.1 第一種方式
//    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];

    //4.2 第二種方式
//    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

    //4.3 第三種方式
    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
}

(6)如何計算代碼段的執(zhí)行時間

//第一種方法
    NSDate *start = [NSDate date];
    //2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進制數(shù)據(jù))
    NSData *data = [NSData dataWithContentsOfURL:url];

    NSDate *end = [NSDate date];
    NSLog(@"第二步操作花費的時間為%f",[end timeIntervalSinceDate:start]);

//第二種方法
    CFTimeInterval start = CFAbsoluteTimeGetCurrent();
    NSData *data = [NSData dataWithContentsOfURL:url];

    CFTimeInterval end = CFAbsoluteTimeGetCurrent();
    NSLog(@"第二步操作花費的時間為%f",end - start);

4.GCD

(1)GCD基本知識

01 兩個核心概念-隊列和任務(wù)
02 同步函數(shù)和異步函數(shù)

(2)GCD基本使用【重點】
2.1注意:1.創(chuàng)建隊列: 1.1 創(chuàng)建隊列

//基本隊列
//第一參數(shù):標識符
//第二個參數(shù):隊列類型
dispatch_queue_t queue = dispatch_queue_create(<#const char *label#>, <#dispatch_queue_attr_t attr#>)

//全局并發(fā)隊列
//第一參數(shù):優(yōu)先級
//第二個參數(shù):系統(tǒng)占位符(0)填零就好了
dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)
Tip:注意:全局并發(fā)隊列不能和柵欄函數(shù)一起使用,只能和自己手動創(chuàng)建的隊列使用(系統(tǒng)默認,未知原因)

//主隊列
//主線程
dispatch_get_main_queue();
Tip:注意:UI刷新需要放在主線程,也就是主隊列中(大部分線程間的通信)

Snip20151222_4.png
同步異步的真正含義:
同步異步函數(shù)只是決定將任務(wù)放在哪個線程執(zhí)行而已歧蕉,并且決定他們的執(zhí)行方式,是同步還是異步的迹炼,如果是同步,任務(wù)的執(zhí)行優(yōu)先等級是很高的,如果放在主線程源武,會和主線程中執(zhí)行其他任務(wù)的優(yōu)先級一樣高,導(dǎo)致誰也不能執(zhí)行想幻,如果是異步粱栖,只是降低了異步函數(shù)中的任務(wù)的執(zhí)行優(yōu)先等級,這樣就不會出現(xiàn)死鎖了脏毯,cpu只會在空閑的時候來處理低等級的任務(wù)闹究!
TIP:模仿主線程死鎖,在子線程嵌套使用同步函數(shù)執(zhí)行任務(wù)食店!
主線程隊列中不能開啟同步渣淤,會阻塞主線程。只能開啟異步任務(wù)吉嫩,開啟異步任務(wù)也不會開啟新的線程价认,只是降低異步任務(wù)的優(yōu)先級,讓cpu空閑的時候才去調(diào)用自娩。而同步任務(wù)用踩,會搶占主線程的資源,會造成死鎖忙迁。
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ā)生)
*死鎖的理解*:因為同步函數(shù)在主線程中會執(zhí)行block中的函數(shù)塊但是在一條線程中是遵循先進先出的原則,所以block會等同步函數(shù)dispatch_sync執(zhí)行,但是dispatch_又等待block調(diào)用,所以形成死鎖
07 注意同步函數(shù)和異步函數(shù)在執(zhí)行順序上面的差異

(3)GCD線程間通信

 //0.獲取一個全局的隊列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //1.先開啟一個線程晨川,把下載圖片的操作放在子線程中處理
    dispatch_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;
           //打印查看當前線程
            NSLog(@"刷新UI---%@",[NSThread currentThread]);
        });

    });

(4)GCD其它常用函數(shù)


    01 柵欄函數(shù)(控制任務(wù)的執(zhí)行順序,因為在并發(fā)過程中,我們無法控制任務(wù)的執(zhí)行先后順序,所以使用這個函數(shù)來控制任務(wù)的執(zhí)行順序)
    dispatch_barrier_async(queue, ^{
        NSLog(@"--dispatch_barrier_async-");
    });

    02 延遲執(zhí)行(延遲·控制在哪個線程執(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 一次性代碼(注意不能放到懶加載如果出現(xiàn)另外創(chuàng)建一個對象的時候,這個對象是創(chuàng)建不出來的,因為這份代碼只能執(zhí)行一次,不像懶加載會再給你創(chuàng)建一個)
    -(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 group,
    dispatch_queue_t queue,
    dispatch_block_t block);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末删豺,一起剝皮案震驚了整個濱河市共虑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呀页,老刑警劉巖妈拌,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡尘分,警方通過查閱死者的電腦和手機猜惋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來培愁,“玉大人著摔,你說我怎么就攤上這事《ㄐ” “怎么了谍咆?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長私股。 經(jīng)常有香客問我摹察,道長,這世上最難降的妖魔是什么倡鲸? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任供嚎,我火速辦了婚禮,結(jié)果婚禮上旦签,老公的妹妹穿的比我還像新娘查坪。我一直安慰自己,他們只是感情好宁炫,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布偿曙。 她就那樣靜靜地躺著,像睡著了一般羔巢。 火紅的嫁衣襯著肌膚如雪望忆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天竿秆,我揣著相機與錄音启摄,去河邊找鬼。 笑死幽钢,一個胖子當著我的面吹牛歉备,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匪燕,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蕾羊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帽驯?” 一聲冷哼從身側(cè)響起龟再,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尼变,沒想到半個月后利凑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年哀澈,在試婚紗的時候發(fā)現(xiàn)自己被綠了牌借。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡日丹,死狀恐怖走哺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哲虾,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布择示,位于F島的核電站束凑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏栅盲。R本人自食惡果不足惜汪诉,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谈秫。 院中可真熱鬧扒寄,春花似錦、人聲如沸拟烫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硕淑。三九已至课竣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間置媳,已是汗流浹背于樟。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拇囊,地道東北人迂曲。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像寥袭,于是被迫代替她去往敵國和親路捧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

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

  • 從哪說起呢纠永? 單純講多線程編程真的不知道從哪下嘴鬓长。。 不如我直接引用一個最簡單的問題尝江,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,757評論 1 17
  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 347,929評論 308 1,926
  • 多線程 在iOS開發(fā)中為提高程序的運行效率會將比較耗時的操作放在子線程中執(zhí)行涉波,iOS系統(tǒng)進程默認啟動一個主線程,用...
    郭豪豪閱讀 2,597評論 0 4
  • 有沒有一種辦法窗声,可以讓任何人做任何事相恃? 很多年前,我剛上大學的時候笨觅,不諳世事拦耐,說什么都不考慮別人的感受。在寢室經(jīng)常...
    唐磊情商閱讀 331評論 0 0
  • 我一生渴望被人收藏好见剩,妥善安放杀糯,細心保存。免我驚苍苞,免我苦固翰,免我四下流離,免我無枝可依羹呵。 但那人骂际,我知,我一直知冈欢,他...
    小小睿有大智慧閱讀 173評論 0 0