iOS開發(fā)網(wǎng)絡多線程之多線程

iOS開發(fā)筆記-多線程01

理論部分:

一.進程

1)概念:是指在系統(tǒng)中正在運行的一個應用程序,每個進程的存儲空間是獨立的(終端中輸入top可以查看進程,按Q退出)

P.S.進程與應用程序的差別:進程是有狀態(tài)的,正在執(zhí)行的

2)進程是CPU進行資源分配與調(diào)度的基本單位

二.線程

1)線程是CPU調(diào)度的基本單位(1個進程想執(zhí)行任務,必須要有線程 ),一個進程中所有的任務都在線程中執(zhí)行

2)一個線程中的任務的執(zhí)行是串行的

P.S.進程與線程的辨析

1)一個程序可以對應多個進程,一個進程中可以有多個線程,但至少要有一個線程,線程是進程的一條路徑

2)同一個進程內(nèi)的線程共享進程的資源

3)進程可以分配資源,而線程不可以

3)多線程并發(fā)執(zhí)行:其實是CPU快速地在多個線程之間調(diào)度(只是假象,因為同一時間,CPU只能處理一條線程),建議開辟線程數(shù)量為3-5條

4)主線程:也稱為UI線程,作用是:1.顯示\刷新UI界面 2.處理UI事件 (所有和UI相關的操作都需要在主線程中執(zhí)行)

打印時,若顯示的number等于1,則為主線程,其他數(shù)字,則為子線程

P.S.主線程注意點

1.不要將耗時的任務放在主線程

2.UI刷新操作要放在主線程中

3.耗時的操作放在子線程中(后臺線程)

三.pthread


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

四.NSThread

1.一個NSThread代表一條線程

2.優(yōu)先級高,cpu調(diào)用的概率高(影響的也是CPU調(diào)度到的概率)


1)NSThread創(chuàng)建線程的四種方式
        //第一種創(chuàng)建線程的方式:alloc initWithTarget.
        //特點:需要手動開啟線程购公,可以拿到線程對象進行詳細設置
            //創(chuàng)建線程
            /*
             第一個參數(shù):目標對象
             第二個參數(shù):選擇器梆造,線程啟動要調(diào)用哪個方法
             第三個參數(shù):前面方法要接收的參數(shù)(最多只能接收一個參數(shù)魄缚,沒有則傳nil)
             */
            NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"hmx"];
             //啟動線程
            [thread start];

        //第二種創(chuàng)建線程的方式:分離出一條子線程
        //特點:自動啟動線程,無法對線程進行更詳細的設置
            /*
             第一個參數(shù):線程啟動調(diào)用的方法
             第二個參數(shù):目標對象
             第三個參數(shù):傳遞給調(diào)用方法的參數(shù)
             */
            [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分離出來的子線程"];

        //第三種創(chuàng)建線程的方式:后臺線程
        //特點:自動啟動線程梗醇,無法進行更詳細設置
            [self performSelectorInBackground:@selector(run:) withObject:@"我是后臺線程"];
        
        //第四種創(chuàng)建線程方法:alloc init
        //新建一個類 繼承自NSThread,重寫內(nèi)部的main方法來封裝任務
            NSThread *thread = [[NSThread alloc]init];
            //啟動線程
            [thread start];

    2)設置線程的屬性
        //設置線程的名稱
        thread.name = @"線程A";

        //設置線程的優(yōu)先級,注意線程優(yōu)先級的取值范圍為0.0~1.0之間,1.0表示線程的優(yōu)先級最高,如果不設置該值撒蟀,那么理想狀態(tài)下默認為0.5
        thread.threadPriority = 1.0;

3.線程狀態(tài)相關問題:

1.線程的各種狀態(tài):新建-就緒-運行-阻塞-死亡
2.當線程的任務執(zhí)行完畢之后就銷毀了
3.當線程放入可調(diào)度線程池中,CPU才會調(diào)度
4.線程已經(jīng)死了,是不能再重新打開的
5.當線程解除阻塞狀態(tài)時,會進入就緒狀態(tài),而不是運行狀態(tài)

4.線程安全相關問題:

    1. 互斥鎖:@synchronized(self){//需要鎖定的代碼}(推薦使用self)
    2. 前提條件:多個線程可能會訪問同一塊資源
    3. 注意點:1)要注意加鎖的位置
             2)鎖對象必須是對象,且全局唯一
             3)加上互斥鎖之后,就會使線程同步(即線程永遠都是按一個順序調(diào)用,例:一開始是2->1->3的順序,之后依舊為2->1->3的順序)
             4)線程是需要消耗性能的
    4. 專業(yè)術語-線程同步
    5. 原子和非原子屬性(是否對setter方法加鎖)
       atomic 線程安全,需要消耗大量資源
       nonatomic 非線程安全,適合內(nèi)存小的移動設備  (開發(fā)中聲明為這個)

5.計算代碼段間的執(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);

6.回到主線程刷新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];
    }

五.PCD

1.GCD基本知識

1) 兩個核心概念:隊列和任務:
    隊列:用來存放任務(決定在哪個線程執(zhí)行任務)
    任務:執(zhí)行什么操作
2) 同步函數(shù)和異步函數(shù)的區(qū)別:
    同步:1.只能在當前線程中執(zhí)行,不具備開啟新線程的能力
        2.執(zhí)行任務的方式:當執(zhí)行到我時必須等我執(zhí)行完才能執(zhí)行后面的任務
    異步:1.可以在新的線程中執(zhí)行任務,具備開啟新線程的能力
        2.執(zhí)行任務的方式:可以不用等我執(zhí)行完畢,就可以直接執(zhí)行后面的任務
3)  串行隊列:1.取出一個任務后,等到該任務執(zhí)行完畢之后,接著去第二個任務
            2.創(chuàng)建方式:a.自己創(chuàng)建  b.主隊列
    并行隊列:1.取出一個任務后,接著執(zhí)行第二個任務
            2.創(chuàng)建方式:a.自己創(chuàng)建  b.全局并發(fā)隊列
    主隊列:1.在安排任務的時候,會先檢查主線程的狀態(tài),如果主線程忙,那么久暫停調(diào)度直到空閑為止
          2.想要實現(xiàn)控制系統(tǒng)開幾條線程時,只需要控制創(chuàng)建幾個隊列
          3.凡是放在主隊列里的任務都在主線程完成

2.GCD基本使用【重要】

01 異步函數(shù)+并發(fā)隊列:開啟多條線程叙谨,并發(fā)執(zhí)行任務
02 異步函數(shù)+串行隊列:開啟一條線程,串行執(zhí)行任務
03 同步函數(shù)+并發(fā)隊列:不開線程保屯,串行執(zhí)行任務
04 同步函數(shù)+串行隊列:不開線程手负,串行執(zhí)行任務
05 異步函數(shù)+主隊列:不開線程,在主線程中串行執(zhí)行任務
06 同步函數(shù)+主隊列:不開線程姑尺,串行執(zhí)行任務(注意死鎖發(fā)生)
   P.S若當前是子線程執(zhí)行的同步函數(shù)加上主隊列的方式,不會發(fā)生死鎖
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相關注意點

1. 開線程的兩個條件:1.必須是異步函數(shù) 2.必須不是主隊列(主線程)
2. 放到主隊列里的任務,必須要在主線程中執(zhí)行(不一定在當前線程中執(zhí)行,即即使在子線程中調(diào)用了主隊列,還是子主線程中調(diào)用)

5.GCD常用函數(shù):

   
   1)柵欄函數(shù)(控制任務的執(zhí)行順序)
        dispatch_barrier_async(queue, ^{
            NSLog(@"--dispatch_barrier_async-");
        });
    /*
    P.S 注意點:1.柵欄函數(shù)可以控制線程的執(zhí)行順序
              2.柵欄函數(shù)不能使用全局并發(fā)隊列
              3.柵欄函數(shù)在執(zhí)行時是獨占的
              4.dispatch_barrier_async == dispatch_async  這兩個是等同的
    */
    
    2)延遲執(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]);
        });
    /*
    Q:GCD的延遲執(zhí)行 是先等2秒再提交 OR 先提交再等2秒?
    A:先等2秒再提交(延遲提交)  因為任務提交到隊列里就不好控制了
    */

    3)一次性代碼(注意不能放到懶加載)
        -(void)once
        {
            //整個程序運行過程中只會執(zhí)行一次
            //onceToken用來記錄該部分的代碼是否被執(zhí)行過
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{

                NSLog(@"-----");
            });
        }
    /*
    一次性代碼的特點:1.整個程序運行過程中只會執(zhí)行一次
                      2.它本身是線程安全的
    */

    4)快速迭代(開多個線程并發(fā)完成迭代操作)
           dispatch_apply(subpaths.count, queue, ^(size_t index) {
        });
     /*
     快速迭代:多個線程(子線程與主線程一起工作的)一起并發(fā)執(zhí)行任務的--->對順序沒有要求時使用
     Q:快速迭代若不是從0開始,怎么處理
     A:初始值若不是0,則不需要使用GCD的快速迭代,使用for循環(huán)即可
     */
    
    5)隊列組(同柵欄函數(shù))--->調(diào)度組
        //創(chuàng)建隊列組
        dispatch_group_t group = dispatch_group_create();
        //隊列組中的任務執(zhí)行完畢之后,執(zhí)行該函數(shù)
        dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);//這個方法本身也是異步的

    /*
    方便管理一個組內(nèi)的操作
    */

    6)進入群組和離開群組
        dispatch_group_enter(group);//執(zhí)行該函數(shù)后切蟋,后面異步執(zhí)行的block會被gruop監(jiān)聽
        dispatch_group_leave(group);//異步block中统捶,所有的任務都執(zhí)行完畢,最后離開群組
       /*
       注意:dispatch_group_enter|dispatch_group_leave必須成對使用
            當需要監(jiān)聽多個任務時,則重復寫一組即可
       */
       //死等方法:知道隊列組中所有都執(zhí)行完畢之后才過掉該方法(同步)
       //diepatch_group_wait(group,DISPATCH_TIME_FOREVER)
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柄粹,一起剝皮案震驚了整個濱河市喘鸟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驻右,老刑警劉巖迷守,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異旺入,居然都是意外死亡,警方通過查閱死者的電腦和手機凯力,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門茵瘾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咐鹤,你說我怎么就攤上這事拗秘。” “怎么了祈惶?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵雕旨,是天一觀的道長。 經(jīng)常有香客問我捧请,道長凡涩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任疹蛉,我火速辦了婚禮活箕,結果婚禮上,老公的妹妹穿的比我還像新娘可款。我一直安慰自己育韩,他們只是感情好克蚂,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筋讨,像睡著了一般埃叭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悉罕,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天赤屋,我揣著相機與錄音,去河邊找鬼蛮粮。 笑死益缎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的然想。 我是一名探鬼主播莺奔,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼变泄!你這毒婦竟也來了令哟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤妨蛹,失蹤者是張志新(化名)和其女友劉穎屏富,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛙卤,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡狠半,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了颤难。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片神年。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖行嗤,靈堂內(nèi)的尸體忽然破棺而出已日,到底是詐尸還是另有隱情,我是刑警寧澤栅屏,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布飘千,位于F島的核電站,受9級特大地震影響栈雳,放射性物質(zhì)發(fā)生泄漏护奈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一哥纫、第九天 我趴在偏房一處隱蔽的房頂上張望逆济。 院中可真熱鬧,春花似錦、人聲如沸奖慌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽简僧。三九已至建椰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岛马,已是汗流浹背棉姐。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留啦逆,地道東北人伞矩。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像夏志,于是被迫代替她去往敵國和親乃坤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

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

  • 從哪說起呢沟蔑? 單純講多線程編程真的不知道從哪下嘴湿诊。。 不如我直接引用一個最簡單的問題瘦材,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,766評論 1 17
  • 什么是進程厅须? 進程是指在系統(tǒng)中正在運行的一個應用程序。 每個進程之間是獨立的食棕,每個進程均運行在其專用且受保護的內(nèi)存...
    珍此良辰閱讀 1,258評論 1 5
  • 歡迎大家指出文章中需要改正或者需要補充的地方朗和,我會及時更新,非常感謝簿晓。 一. 多線程基礎 1. 進程 進程是指在系...
    xx_cc閱讀 7,197評論 11 70
  • 背景 擔心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了眶拉!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似抢蚀。...
    Dely閱讀 9,245評論 21 42
  • Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼镰禾,方法是什么皿曲?如果想延時執(zhí)行代碼、方法又是什么吴侦? 1...
    AlanGe閱讀 1,748評論 0 17