ios多線程

  • 什么是進(jìn)程

  • 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序

  • 每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi)

  • 比如同時(shí)打開(kāi)迅雷、Xcode,系統(tǒng)就會(huì)分別啟動(dòng)2個(gè)進(jìn)程

  • 什么是線程

  • 1個(gè)進(jìn)程要想執(zhí)行任務(wù),必須得有線程(每1個(gè)進(jìn)程至少要有1條線程)

  • 一個(gè)進(jìn)程(程序)的所有任務(wù)都在線程中執(zhí)行

  • 比如使用酷狗播放音樂(lè)、使用迅雷下載電影,都需要在線程中執(zhí)行

  • 1個(gè)線程中任務(wù)的執(zhí)行是串行的

  • 如果要在1個(gè)線程中執(zhí)行多個(gè)任務(wù),那么只能一個(gè)一個(gè)地按順序執(zhí)行這些任務(wù)

  • 也就是說(shuō),在同一時(shí)間內(nèi),1個(gè)線程只能執(zhí)行1個(gè)任務(wù)

什么是多線程
  • 1個(gè)進(jìn)程中可以開(kāi)啟多條線程,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù)
  • 多線程技術(shù)可以提高程序的執(zhí)行效率
  • 比如同時(shí)開(kāi)啟3條線程分別下載3個(gè)文件(分別是文件A、文件B、文件C
多線程的原理
  • 同一時(shí)間,CPU只能處理1條線程,只有1條線程在工作(執(zhí)行)
  • 多線程并發(fā)(同時(shí))執(zhí)行,其實(shí)是CPU快速地在多條線程之間調(diào)度(切換)
  • 如果CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程并發(fā)執(zhí)行的假象

如果線程非常非常多,會(huì)發(fā)生什么情況?
CPU會(huì)在N多線程之間調(diào)度,CPU會(huì)累死,消耗大量的CPU資源
每條線程被調(diào)度執(zhí)行的頻次會(huì)降低(線程的執(zhí)行效率降低)

多線程的優(yōu)點(diǎn)
  • 能適當(dāng)提高程序的執(zhí)行效率
  • 能適當(dāng)提高資源利用率(CPU、內(nèi)存利用率)
多線程的缺點(diǎn)
  • 創(chuàng)建線程是有開(kāi)銷(xiāo)的,iOS下主要成本包括:內(nèi)核數(shù)據(jù)結(jié)構(gòu)(大約1KB)、??臻g(子線程512KB、主線程1MB,也可以使用-setStackSize:設(shè)置,但必須是4K的倍數(shù),而且最小是16K),創(chuàng)建線程大約需要90毫秒的創(chuàng)建時(shí)間
  • 如果開(kāi)啟大量的線程,會(huì)降低程序的性能
  • 線程越多,CPU在調(diào)度線程上的開(kāi)銷(xiāo)就越大
  • 程序設(shè)計(jì)更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享
什么是主線程
  • 一個(gè)iOS程序運(yùn)行后,默認(rèn)會(huì)開(kāi)啟1條線程,稱為“主線程”或“UI線程”

  • 主線程的主要作用

    • 顯示\刷新UI界面
    • 處理UI事件(比如點(diǎn)擊事件、滾動(dòng)事件、拖拽事件等)
  • 主線程的使用注意

    • 別將比較耗時(shí)的操作放到主線程中
    • 耗時(shí)操作會(huì)卡住主線程,嚴(yán)重影響UI的流暢度,給用戶一種“卡”的壞體驗(yàn)

在主線程放一個(gè)需要耗時(shí)10秒的操作;用戶在第五秒的時(shí)候點(diǎn)擊屏幕按鈕,在第十秒的時(shí)候才會(huì)做出響應(yīng);造成卡頓現(xiàn)象;

  • 在ios領(lǐng)域里面真正的多線程技術(shù)只有這兩個(gè)pthread和NSthread;
    GCD不能直接操作多線程;屬于并發(fā)技術(shù);NSOperation也是一樣,是操作隊(duì)列的,與線程無(wú)關(guān),線程部分GCD已經(jīng)幫你封裝好了!
  • GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷(xiāo)毀線程)
  • 我們只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫(xiě)任何線程管理代碼
  • 蘋(píng)果不建議開(kāi)發(fā)者使用多線程技術(shù);
    鼓勵(lì)使用并發(fā)技術(shù);
NSThread
  • 創(chuàng)建線程的幾種方法
// 創(chuàng)建一個(gè)NSThread
NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(demo:) object:@"Thread"];
//線程就緒-之后等著cpu調(diào)度; 
[thread start];

//demo函數(shù)在子線程執(zhí)行
-(void)demo:(id)obj{
    for (int i = 0; i < 2; i++) {
        //number !=1
        NSLog(@"%@",[NSThread currentThread]);
        //[NSThread currentThread] 打印當(dāng)前線程   
        //返回一個(gè)Thread對(duì)象,里面有number和name屬性
        //number == 1 說(shuō)明是主線程   number != 1 就是其他線程
    }
}

//detach ==> 分離
//分離出一條子線程
[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"];

//InBackground 就是在后臺(tái)(子線程)運(yùn)行!!
//是NSObject的分類(lèi) 意味著所有的繼承NSObject的都可以使用這個(gè)方法
//非常方便.不用NSThread對(duì)象
[self performSelectorInBackground:@selector(demo:) withObject:@"background"];

線程的狀態(tài)
  • 新建一條線程,線程在可調(diào)度線程池里 (由cpu進(jìn)行調(diào)度的)
  • 當(dāng) [thread start] 的時(shí)候,在可調(diào)度線程池里的線程都處于就緒狀態(tài)
  • cpu調(diào)度處于就緒狀態(tài)的線程
  • 運(yùn)行狀態(tài)
  • 線程執(zhí)行完畢之后線程在可調(diào)度線程池取出,干掉;

線程阻塞

  • 當(dāng)運(yùn)行滿足某個(gè)條件,會(huì)讓線程"睡一會(huì)

提示:sleep 方法是類(lèi)方法,會(huì)直接休眠當(dāng)前線程!!

//當(dāng)前線程睡兩秒
[NSThread sleepForTimeInterval:2.0];
//一旦強(qiáng)行終止線程,后續(xù)的所有代碼都不會(huì)被執(zhí)行
//注意:在終止線程之前,應(yīng)該要釋放之前分配的對(duì)象!!
[NSThread exit];
//創(chuàng)建線程
NSThread * t = [[NSThread alloc]initWithTarget:self selector:@selector(theadStatus) object:nil];
//線程就緒(CPU翻牌)
[t start];

-(void)theadStatus{
    for (int i = 0; i < 20;i++) {
        //阻塞,當(dāng)運(yùn)行滿足某個(gè)條件,會(huì)讓線程"睡一會(huì)"
        //提示:sleep 方法是類(lèi)方法,會(huì)直接休眠當(dāng)前線程!!
        if (i == 8) {
            NSLog(@"睡一會(huì)");    
            //睡的是子線程 
            //注意!!! exit會(huì)殺掉主線程!但是APP不會(huì)掛掉!!
             [NSThread sleepForTimeInterval:2.0];
        }
        NSLog(@"%@  %d",[NSThread currentThread],i);
        
        //當(dāng)線程滿足某一個(gè)條件時(shí),可以強(qiáng)行終止的
        //exit 類(lèi)方法,哥么終止當(dāng)前線程!!!!
        if (i == 15) {
            [NSThread exit];  //線程就就處于死亡狀態(tài)了
        }
    }
    NSLog(@"能來(lái)嗎???");  //來(lái)不了了
}

threadPriority  //線程優(yōu)先級(jí)
  • 優(yōu)先級(jí)只是保證cpu調(diào)度的可能性會(huì)高!
    用優(yōu)先級(jí)來(lái)控制線程得執(zhí)行順序是不理性的!
  • 建議:再開(kāi)發(fā)的時(shí)候不要修改優(yōu)先級(jí);
    在多線程的開(kāi)發(fā)中,不要相信一次的運(yùn)行結(jié)果!
多線程的目的
  • 將耗時(shí)操作放在后臺(tái),不阻塞UI線程

多線程的安全隱患

  • 1塊資源可能會(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)題

安全隱患的解決 - 互斥鎖
  • 一個(gè)線程訪問(wèn)一個(gè)資源時(shí),先給他上鎖,訪問(wèn)完成之后再解鎖讓其他線程訪問(wèn);
  • 互斥鎖 -- 保證鎖內(nèi)的代碼,同一時(shí)間,只有一條線程執(zhí)行!
  • 互斥鎖 的范圍 應(yīng)該盡量小,范圍大了 效率就差!!
        //互斥鎖
        @synchronized (self) {
            //括號(hào)里是 同一時(shí)間只能有一條線程執(zhí)行的代碼
        };

好比你去上廁所,你把門(mén)鎖上了,別人只能在外面等著,等你操作完廁所,別人才能進(jìn)來(lái);如果你不鎖門(mén),兩個(gè)人在廁所后果不堪設(shè)想!??

原子屬性
  • atomic-用來(lái)保護(hù)線程安全(多線程執(zhí)行寫(xiě)入操作的時(shí)候,保證同一時(shí)間只有一個(gè)線程執(zhí)行寫(xiě)入 只對(duì)寫(xiě)入操作上鎖,讀不上鎖)
  • 單寫(xiě)多讀的原子屬性(只能單個(gè)線程寫(xiě),但可以多個(gè)線程讀)
  • 實(shí)際上原子屬性內(nèi)部有一把鎖叫 - 自旋鎖
    • 自旋鎖&互斥鎖異同
      • 共同點(diǎn)

        • 都能保證線程安全
      • 不同點(diǎn)

        • 互斥鎖:被鎖在外面的線程,處于休眠狀態(tài);等待鎖打開(kāi),然后被喚醒;
        • 自旋鎖:被鎖在外面的線程,用死循環(huán)的方式,等待鎖打開(kāi);
  • 不管什么鎖,都很消耗性能,效率不高;

想要模擬原子屬性的時(shí)候就在set方法里加了一把鎖; @synchronized
如果不寫(xiě)nonatomic | atomic 默認(rèn)是 atomic

線程間的通信方法

  • 就這五個(gè)方法
    • 把SEL丟到某一個(gè)線程去執(zhí)行
/**
 waitUntilDone : 當(dāng)前線程是否等待SEL執(zhí)行完再繼續(xù)
*/

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
    // equivalent to the first method with kCFRunLoopCommonModes

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
    // equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);


GCD(重點(diǎn))

GCD并不是多線程技術(shù);屬于并發(fā)解決技術(shù);

  • GCD是蘋(píng)果為了適配多核的并行運(yùn)算提出的解決方案
  • GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核、四核)
  • GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷(xiāo)毀線程)
  • 程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫(xiě)任何線程管理代碼
GCD的使用就2個(gè)步驟
  • 定制任務(wù)

  • 將任務(wù)添加到隊(duì)列中

GCD中有2個(gè)核心概念
  • 任務(wù):執(zhí)行什么操作
    • 執(zhí)行任務(wù)方式有兩種; 同步/異步
      • 同步:不會(huì)到線程池里面去獲取子線程!
      • 異步:只要有任務(wù),就會(huì)到線程池取子線程!(主隊(duì)列除外!)
  • 隊(duì)列:用來(lái)存放任務(wù)
    • 串行:一個(gè)接一個(gè)的調(diào)度任務(wù)
    • 并行:可以同時(shí)調(diào)度多個(gè)任務(wù)

GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出,放到對(duì)應(yīng)的線程中執(zhí)行
任務(wù)的取出遵循隊(duì)列的FIFO原則:先進(jìn)先出,后進(jìn)后出

/**
 同步執(zhí)行方法,這句話不執(zhí)行完,就不會(huì)執(zhí)行下一個(gè)任務(wù),同步執(zhí)行不會(huì)開(kāi)啟線程
 */
   //1.創(chuàng)建隊(duì)列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //2.任務(wù)添加到隊(duì)列中
    //2.1 定義任務(wù) -- block
    void(^task)() = ^{
        NSLog(@"%@",[NSThread currentThread]);
    };
    //2.2 添加任務(wù)到隊(duì)列,并且會(huì)執(zhí)行
    dispatch_sync(q, task);
/**
 異步執(zhí)行任務(wù)  哥么如果任務(wù)沒(méi)有執(zhí)行完畢,可以不用等待,異步執(zhí)行下一個(gè)任務(wù) 
 具備開(kāi)啟線程的能力!  異步通常又是多線程的代名詞!!
 */
-(void)gcdDemo2{
    //1.創(chuàng)建隊(duì)列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //2 定義任務(wù) -- block
    void(^task)() = ^{
        NSLog(@"%@",[NSThread currentThread]);
    };
    //3. 添加任務(wù)到隊(duì)列
    dispatch_async(q, task);
}
//線程間通信-切換子線程到主線程更新UI
//指定任務(wù)執(zhí)行方法 -- 異步
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //耗時(shí)操作
        NSLog(@"%@",[NSThread currentThread]);
        
        //更新UI 主隊(duì)列,就是專門(mén)負(fù)責(zé)在主線程上調(diào)度任務(wù)的隊(duì)列!
        //dispatch_get_main_queue  主隊(duì)列 住能操作主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"更新UI%@",[NSThread currentThread]);
            
        });
        
    });
//MARK:串行隊(duì)列,同步任務(wù)
/**
*   不會(huì)開(kāi)啟線程,會(huì)順序執(zhí)行
*/
-(void)gcdDemo1{
    //1.隊(duì)列 - 串行
    
    /**
     1."ios" 隊(duì)列名稱:
     2. NULL 隊(duì)列的屬性: DISPATCH_QUEUE_SERIAL 表示串行!
     */
    dispatch_queue_t q = dispatch_queue_create("ios", NULL);
    
    //2.同步執(zhí)行任務(wù)
    for (int i = 0; i < 10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d",[NSThread currentThread],i);
        });
    }
}
//MARK: 串行隊(duì)列,異步任務(wù)
-(void)gcdDemo2{
    /**
     會(huì)開(kāi)幾條線程?會(huì)順序執(zhí)行嗎?
     開(kāi)一條線程,順序執(zhí)行
     */
    //1.隊(duì)列 - 串行
    dispatch_queue_t q = dispatch_queue_create("tanzhouios", NULL);
    
    //2.異步執(zhí)行任務(wù)
    for (int i = 0; i < 10; i++) {
        NSLog(@"%d------------",i);
        dispatch_async(q, ^{
            NSLog(@"%@ %d",[NSThread currentThread],i);
        });
    }
    //哥么在主線程!
    NSLog(@"come here");
}
//MARK : 并發(fā)隊(duì)列,異步執(zhí)行
-(void)gcdDemo3{
    //1.隊(duì)列 - 并發(fā) DISPATCH_QUEUE_CONCURRENT
    dispatch_queue_t q = dispatch_queue_create("tanzhouios", DISPATCH_QUEUE_CONCURRENT);
    
    //2.異步執(zhí)行任務(wù)
    for (int i = 0; i < 10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d",[NSThread currentThread],i);
        });
    }
    //哥么在主線程!
    NSLog(@"come here");
}
//MARK : 并發(fā)隊(duì)列,同步執(zhí)行   和 串行隊(duì)列,同步執(zhí)行 效果一樣!
-(void)gcdDemo4{
    
    // 會(huì)開(kāi)線程嗎?  順序執(zhí)行?  come here?
    //  不會(huì)          順序     最后
    
    //1.隊(duì)列 - 并發(fā) DISPATCH_QUEUE_CONCURRENT
    dispatch_queue_t q = dispatch_queue_create("tanzhouios", DISPATCH_QUEUE_CONCURRENT);
    
    //2.同步執(zhí)行任務(wù)
    for (int i = 0; i < 10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d",[NSThread currentThread],i);
        });
    }
    //哥么在主線程!
    NSLog(@"come here");
}

小結(jié):
只有異步才會(huì)開(kāi)啟子線程!同步不開(kāi)啟!
開(kāi)幾條線程,取決于隊(duì)列,串行開(kāi)一條,并發(fā)可以開(kāi)多條(異步)

個(gè)人理解鎖這個(gè)問(wèn)題

線程鎖:是多條線程同時(shí)訪問(wèn)一個(gè)資源時(shí)需要一個(gè)互斥鎖;
GDC-死鎖:主隊(duì)列是一個(gè)串行隊(duì)列;在主隊(duì)列里添加一個(gè)同步任務(wù)會(huì)造成死鎖;互相等待的局面;

    //主隊(duì)列是專門(mén)負(fù)責(zé)在主線程上調(diào)度任務(wù)的隊(duì)列 --> 不會(huì)開(kāi)線程
    //1.隊(duì)列 --> 已啟動(dòng)主線程,就可以獲取主隊(duì)列
    dispatch_queue_t q = dispatch_get_main_queue();
    
    //2.同步任務(wù)  ==> 死鎖
    //走到這里添加一個(gè)同步任務(wù),主隊(duì)列的任務(wù)是不是要等他執(zhí)行完了在執(zhí)行;
    dispatch_sync(q, ^{
        NSLog(@"能來(lái)嗎? ");
        //主隊(duì)列里的任務(wù)沒(méi)執(zhí)行完呢你想執(zhí)行這同步任務(wù),你是不是要等主隊(duì)列執(zhí)行完了才能執(zhí)行;
    });
    NSLog(@"come here");
死鎖

注意:
主隊(duì)列不是全局隊(duì)列
全局隊(duì)列:dispatch_get_global_queue
全局隊(duì)列本質(zhì)上是并發(fā)隊(duì)列
主隊(duì)列:dispatch_get_main_queue()
主隊(duì)列是一個(gè)串行隊(duì)列

主隊(duì)列是串行的 主隊(duì)列里的任務(wù)默認(rèn)只有一個(gè)(不手動(dòng)添加的話) 這個(gè)任務(wù)是同步的 主隊(duì)列里直接添加一個(gè)異步任務(wù) 不開(kāi)開(kāi)啟子線程

主隊(duì)列只負(fù)責(zé)主線程

    //主隊(duì)列是專門(mén)負(fù)責(zé)在主線程上調(diào)度任務(wù)的隊(duì)列 --> 不會(huì)開(kāi)線程
    
    //1.隊(duì)列 --> 一啟動(dòng)主線程,就可以獲取主隊(duì)列
    dispatch_queue_t q = dispatch_get_main_queue();
    
    //2.異步任務(wù)
    dispatch_async(q, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"come here");
    //全局隊(duì)列
    /*  參數(shù)
     1. 涉及到系統(tǒng)適配
     iOS 8   服務(wù)質(zhì)量
     QOS_CLASS_USER_INTERACTIVE    用戶交互(希望線程快速被執(zhí)行,不要用好使的操作)
     QOS_CLASS_USER_INITIATED      用戶需要的(同樣不要使用耗時(shí)操作)
     QOS_CLASS_DEFAULT             默認(rèn)的(給系統(tǒng)來(lái)重置隊(duì)列的)
     QOS_CLASS_UTILITY             使用工具(用來(lái)做耗時(shí)操作)
     QOS_CLASS_BACKGROUND          后臺(tái)
     QOS_CLASS_UNSPECIFIED         沒(méi)有指定優(yōu)先級(jí)
     iOS 7  調(diào)度的優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_HIGH 2               高優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_DEFAULT 0            默認(rèn)優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_LOW (-2)             低優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后臺(tái)優(yōu)先級(jí)
     
     提示:尤其不要選擇BACKGROUND 優(yōu)先級(jí),服務(wù)質(zhì)量,線程執(zhí)行會(huì)慢到令人發(fā)指!!!
     
     
     2. 為未來(lái)使用的一個(gè)保留,現(xiàn)在始終給0.
     
     老項(xiàng)目中,一般還是沒(méi)有淘汰iOS 7  ,沒(méi)法使用服務(wù)質(zhì)量
     */
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //以第一個(gè)0用來(lái)設(shè)置優(yōu)先級(jí)
    //第二個(gè)0還沒(méi)有定義
    /*
     全局隊(duì)列 & 并發(fā)隊(duì)列   區(qū)別
     1> 名稱,并發(fā)隊(duì)列取名字,適合于企業(yè)開(kāi)發(fā)跟蹤錯(cuò)誤
     2> release,在MRC 并發(fā)隊(duì)列 需要使用的
        dispatch_release(q);//ARC 情況下不需要release !
     
     
     全局隊(duì)列 & 串行隊(duì)列
        全局隊(duì)列: 并發(fā),能夠調(diào)度多個(gè)線程,執(zhí)行效率高
            - 費(fèi)電
        串行隊(duì)列:一個(gè)一個(gè)執(zhí)行,執(zhí)行效率低
            - 省點(diǎn)
     
        判斷依據(jù):用戶上網(wǎng)方式
            - WIFI : 可以多開(kāi)線程
            - 流量  : 盡量少開(kāi)線程
     
     */
    //1.隊(duì)列
    dispatch_queue_t q = dispatch_queue_create("tanzhou", DISPATCH_QUEUE_CONCURRENT);
    //2.全局隊(duì)列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);

 延遲執(zhí)行
    /**
     從現(xiàn)在開(kāi)始,進(jìn)過(guò)多少納秒之后,讓 queue隊(duì)列,調(diào)度 block 任務(wù),異步執(zhí)行!
     參數(shù):
     1.when
     2.queue
     3.block
     */
    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.00003 * NSEC_PER_SEC));
    dispatch_after(when, dispatch_queue_create("tanzhou", NULL), ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
GCD:執(zhí)行一次 常用于單利
    //蘋(píng)果提供的 一次執(zhí)行機(jī)制,不僅能夠保證一次執(zhí)行!而且是線程安全的!!
    static dispatch_once_t onceToken;
    NSLog(@"%ld",onceToken);
    //蘋(píng)果推薦使用 gcd 一次執(zhí)行,效率高
    //不要使用互斥鎖,效率低!
    dispatch_once(&onceToken, ^{
        //只會(huì)執(zhí)行一次!!
        NSLog(@"執(zhí)行了%@",[NSThread currentThread]);
    });
GCD調(diào)度組
 //1.隊(duì)列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    
    //2.調(diào)度組
    dispatch_group_t g = dispatch_group_create();
    
    //3.添加任務(wù),讓隊(duì)列調(diào)度,任務(wù)執(zhí)行情況,最后通知群組
    dispatch_group_async(g, q, ^{
        NSLog(@"download A%@",[NSThread currentThread]);
    });
    dispatch_group_async(g, q, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"download B%@",[NSThread currentThread]);
    });
    dispatch_group_async(g, q, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"download C%@",[NSThread currentThread]);
    });
    
    //4.所有任務(wù)執(zhí)行完畢后,通知
    //用一個(gè)調(diào)度組,可以監(jiān)聽(tīng)全局隊(duì)列的任務(wù),主隊(duì)列去執(zhí)行最后的任務(wù)
    //dispatch_group_notify 本身也是異步的!
    dispatch_group_notify(g, dispatch_get_main_queue(), ^{
        //更新UI,通知用戶
        NSLog(@"OK %@",[NSThread currentThread]);
    });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 多線程 在iOS開(kāi)發(fā)中為提高程序的運(yùn)行效率會(huì)將比較耗時(shí)的操作放在子線程中執(zhí)行,iOS系統(tǒng)進(jìn)程默認(rèn)啟動(dòng)一個(gè)主線程,用...
    郭豪豪閱讀 2,719評(píng)論 0 4
  • 又來(lái)到了一個(gè)老生常談的問(wèn)題,應(yīng)用層軟件開(kāi)發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問(wèn)題開(kāi)始,來(lái)談?wù)劜?..
    tangsl閱讀 4,317評(píng)論 0 23
  • 歡迎大家指出文章中需要改正或者需要補(bǔ)充的地方,我會(huì)及時(shí)更新,非常感謝。 一. 多線程基礎(chǔ) 1. 進(jìn)程 進(jìn)程是指在系...
    xx_cc閱讀 7,371評(píng)論 11 70
  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,602評(píng)論 1 33
  • 在情人節(jié)這天,已經(jīng)不再想著收什么禮物了,因?yàn)槔瞎珡膩?lái)沒(méi)有送過(guò)禮物,不同的是,自己不再期盼不再少女心。 今年的情人節(jié)...
    韋陀閱讀 242評(píng)論 0 1

友情鏈接更多精彩內(nèi)容