多線程-GCD

前言

GCD是蘋(píng)果為多核的并行運(yùn)算提出的解決方案,所以會(huì)自動(dòng)合理地利用更多的CPU內(nèi)核(比如雙核、四核),最重要的是它會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷(xiāo)毀線程),完全不需要我們管理,我們只需要告訴干什么就行。同時(shí)GCD抽象層次最高,當(dāng)然是用起來(lái)也最簡(jiǎn)單,只是它基于C語(yǔ)言開(kāi)發(fā),并不像NSOperation是面向?qū)ο蟮拈_(kāi)發(fā),而是完全面向過(guò)程的。


GCD是一種輕量的基于block的線程模型,底層實(shí)現(xiàn)主要有Dispatch Queue和Dispatch Source
Dispatch Queue :管理block(操作)
Dispatch Source :處理事件
Dispatch Queue&Dispatch Source更多相關(guān)知識(shí)

GCD推出來(lái)以后,開(kāi)發(fā)者可以不直接操縱線程,而是將所要執(zhí)行的任務(wù)封裝成一個(gè)unit丟給線程池去處理,線程池會(huì)有效管理線程的并發(fā),控制線程的生死。因此,現(xiàn)在如果考慮到并發(fā)場(chǎng)景,基本上是圍繞著GCD和NSOperationQueue來(lái)展開(kāi)討論。

任務(wù)和隊(duì)列

這里就不得不提到兩個(gè)概念:任務(wù)和隊(duì)列

  • 任務(wù):即操作,就是一段代碼,在 GCD 中就是一個(gè) Block,所以添加任務(wù)十分方便。調(diào)度隊(duì)列執(zhí)行任務(wù)有兩種方式: 同步執(zhí)行 和 異步執(zhí)行.

同步派發(fā)(sync) 和 異步派發(fā)(async) 的主要區(qū)別在于會(huì)不會(huì)阻塞當(dāng)前線程,直到 Block 中的任務(wù)執(zhí)行完畢!

【異步并不一定會(huì)開(kāi)啟多線程,當(dāng)在主線程中派發(fā)任務(wù)到主隊(duì)列后,會(huì)等待主線程空閑時(shí)才會(huì)調(diào)度該任務(wù)并沒(méi)有開(kāi)啟新的線程;添加到其他線程時(shí),會(huì)開(kāi)啟新的線程調(diào)度任務(wù)。】
如果是 同步(sync) 操作,它會(huì)阻塞當(dāng)前線程并等待 Block 中的任務(wù)執(zhí)行完畢,然后當(dāng)前線程才會(huì)繼續(xù)往下運(yùn)行。
如果是 異步(async)操作,當(dāng)前線程會(huì)直接往下執(zhí)行,它不會(huì)阻塞當(dāng)前線程。

  • 隊(duì)列:調(diào)度隊(duì)列是一個(gè)類(lèi)似對(duì)象的結(jié)構(gòu)體,它管理您提交給它的任務(wù)。所有的調(diào)度隊(duì)列都是先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。隊(duì)列和線程的區(qū)別,他們之間并沒(méi)有“擁有關(guān)系(ownership)”。隊(duì)列用于存放任務(wù)。一共有兩種隊(duì)列, 串行隊(duì)列 和 并行隊(duì)列

放到串行隊(duì)列的任務(wù),GCD 會(huì) FIFO(先進(jìn)先出) 地取出來(lái)一個(gè),執(zhí)行一個(gè),然后取下一個(gè),這樣一個(gè)一個(gè)的執(zhí)行。

放到并行隊(duì)列的任務(wù),GCD 也會(huì) FIFO的取出來(lái),但不同的是,它取出來(lái)一個(gè)就會(huì)放到別的線程,然后再取出來(lái)一個(gè)又放到另一個(gè)的線程。這樣由于取的動(dòng)作很快,忽略不計(jì),看起來(lái),所有的任務(wù)都是一起執(zhí)行的。不過(guò)需要注意,GCD 會(huì)根據(jù)系統(tǒng)資源控制并行的數(shù)量,所以如果任務(wù)很多,它并不會(huì)讓所有任務(wù)同時(shí)執(zhí)行。

GCD中不同隊(duì)列中不同任務(wù)的執(zhí)行情況如下表:

同步執(zhí)行的任務(wù) 異步執(zhí)行的任務(wù)
串行隊(duì)列中 當(dāng)前線程,一個(gè)一個(gè)執(zhí)行 其他線程,一個(gè)一個(gè)執(zhí)行
并行隊(duì)列中 當(dāng)前線程,一個(gè)一個(gè)執(zhí)行 同時(shí)開(kāi)很多線程,一起執(zhí)行

隊(duì)列的創(chuàng)建和執(zhí)行
#開(kāi)辟隊(duì)列的方法:
dispatch_queue_t myQueue = dispatch_queue_create("MyQueue", NULL);

  參數(shù)1:標(biāo)簽,用于區(qū)分隊(duì)列
  參數(shù)2:隊(duì)列的類(lèi)型,表示這個(gè)隊(duì)列是串行隊(duì)列還是并發(fā)隊(duì)列NUll表示串行隊(duì)列,
  DISPATCH_QUEUE_SERIAL 或 NULL 表示創(chuàng)建串行隊(duì)列。       
  DISPATCH_QUEUE_CONCURRENT 表示創(chuàng)建并行隊(duì)列。   

 #執(zhí)行隊(duì)列的方法
  異步執(zhí)行
  dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

   同步執(zhí)行
  dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)

幾個(gè)特別的隊(duì)列

  • 主隊(duì)列(Main Queue):專門(mén)負(fù)責(zé)調(diào)度主線程(Main Thread)的任務(wù),是一個(gè)串行隊(duì)列,沒(méi)有辦法開(kāi)辟新的線程。任何需要刷新 UI 的工作都要在主隊(duì)列執(zhí)行,所以一般耗時(shí)的任務(wù)都要放到別的線程執(zhí)行。

這里需要特別說(shuō)一下:主隊(duì)列和主線程的關(guān)系
(1)主隊(duì)列是專門(mén)負(fù)責(zé)調(diào)度主線程的任務(wù)的。iOS編程中,需要在主線程(主線程,這個(gè)線程是其他線程的父線程)中進(jìn)行操作時(shí),我們經(jīng)常會(huì)用到以下代碼:
dispatch_async(dispatch_get_main_queue(), ^{
// dispatch_get_main_queue() 實(shí)際獲取的是 主隊(duì)列
});

而且在主隊(duì)列下的任務(wù)不管是異步任務(wù)還是同步任務(wù)都不會(huì)開(kāi)辟線程,任務(wù)只會(huì)在主線程順序執(zhí)行。比如block內(nèi)的任務(wù)是異步執(zhí)行,主線程在將當(dāng)前方法執(zhí)行完畢之后,才會(huì)去繼續(xù)執(zhí)行主隊(duì)列里的任務(wù)。
(2)主隊(duì)列的任務(wù)一定在主線程中執(zhí)行,主線程是可以執(zhí)行主隊(duì)列之外(dispatch_get_global_queue)其他隊(duì)列的任務(wù)的。
另外關(guān)于主線程中更新UI操作也不是絕對(duì)安全的,詳細(xì)請(qǐng)看這篇文章:主線程中也不絕對(duì)安全的 UI 操作

  • 全局隊(duì)列:本質(zhì)是一個(gè)并發(fā)隊(duì)列,由系統(tǒng)提供,是所有應(yīng)用程序共享的。方便編程,可以不用創(chuàng)建就直接使用。

     #獲取全局隊(duì)列的方法:
     dispatch_get_global_queue(long indentifier.unsigned long flags)
    第一個(gè)參數(shù):線程優(yōu)先級(jí),默認(rèn)寫(xiě)0就行,不要使用系統(tǒng)提供的枚舉類(lèi)型,因?yàn)閕os7和ios8的枚舉數(shù)值不一樣,使用數(shù)字可以通用。
    第二個(gè)參數(shù):標(biāo)記參數(shù),目前沒(méi)有用,一般傳入0.
    
    #使用全局隊(duì)列多線程執(zhí)行任務(wù)
     dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     #創(chuàng)建多個(gè)線程用于填充圖片
     for (int i=0; i<count; ++i) {
         #異步執(zhí)行隊(duì)列任務(wù)
         dispatch_async(globalQueue, ^{
             [self loadImage:[NSNumber numberWithInt:i]];
         });
     }
    

隊(duì)列組

隊(duì)列組可以將很多隊(duì)列添加到一個(gè)組里,這樣做的好處是,當(dāng)這個(gè)組里所有的任務(wù)都執(zhí)行完了,隊(duì)列組會(huì)通過(guò)一個(gè)方法通知我們。這是一個(gè)很實(shí)用的功能。

# 創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
# 獲取到全局隊(duì)列
dispatch_queue_t queue =   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

# 多次使用隊(duì)列組的方法執(zhí)行任務(wù), 目前API中只有異步方法
//1.執(zhí)行3次循環(huán)
dispatch_group_async(group, queue, ^{
    for (NSInteger i = 0; i < 3; i++) {
        NSLog(@"group-01 - %@", [NSThread currentThread]);
    }
});

//2.主隊(duì)列執(zhí)行8次循環(huán)
dispatch_group_async(group, dispatch_get_main_queue(), ^{
    for (NSInteger i = 0; i < 8; i++) {
        NSLog(@"group-02 - %@", [NSThread currentThread]);
    }
});

//3.執(zhí)行5次循環(huán)
dispatch_group_async(group, queue, ^{
    for (NSInteger i = 0; i < 5; i++) {
        NSLog(@"group-03 - %@", [NSThread currentThread]);
    }
});

#.都完成后會(huì)自動(dòng)通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"完成 - %@", [NSThread currentThread]);
});

隊(duì)列組其他實(shí)用方法
這也是使用GCD信號(hào)量實(shí)現(xiàn)多線程同步加鎖的實(shí)現(xiàn)方式。

dispatch_group_enter

用于添加對(duì)應(yīng)任務(wù)組中的未執(zhí)行完畢的任務(wù)數(shù),執(zhí)行一次,未執(zhí)行完畢的任務(wù)數(shù)加1,當(dāng)未執(zhí)行完畢任務(wù)數(shù)為0的時(shí)候,才會(huì)使dispatch_group_wait解除阻塞和dispatch_group_notify的block執(zhí)行

void dispatch_group_enter(dispatch_group_t group);

dispatch_group_leave

用于減少任務(wù)組中的未執(zhí)行完畢的任務(wù)數(shù),執(zhí)行一次,未執(zhí)行完畢的任務(wù)數(shù)減1,dispatch_group_enter和dispatch_group_leave要匹配,不然系統(tǒng)會(huì)認(rèn)為group任務(wù)沒(méi)有執(zhí)行完畢

void dispatch_group_leave(dispatch_group_t group);

dispatch_group_wait

等待組任務(wù)完成,會(huì)阻塞當(dāng)前線程,當(dāng)任務(wù)組執(zhí)行完畢時(shí),才會(huì)解除阻塞當(dāng)前線程

long dispatch_group_wait(dispatch_group_t group, 
                     dispatch_time_t timeout);
***********************************
group   ——需要等待的任務(wù)組
timeout ——等待的超時(shí)時(shí)間(即等多久),單位為dispatch_time_t。
如果設(shè)置為DISPATCH_TIME_FOREVER,則會(huì)一直等待(阻塞當(dāng)前線程),直到任務(wù)組執(zhí)行完畢。

信號(hào)量

當(dāng)我們?cè)谔幚硪幌盗芯€程的時(shí)候,當(dāng)數(shù)量達(dá)到一定量,在以前我們可能會(huì)選擇使用NSOperationQueue來(lái)處理并發(fā)控制,但如何在GCD中快速的控制并發(fā)呢?答案就是
dispatch_semaphore.

信號(hào)量是一個(gè)整形值并且具有一個(gè)初始計(jì)數(shù)值,并且支持兩個(gè)操作:信號(hào)通知和等待。當(dāng)一個(gè)信號(hào)量被信號(hào)通知,其計(jì)數(shù)會(huì)被增加。當(dāng)一個(gè)線程在一個(gè)信號(hào)量上等待時(shí),線程會(huì)被阻塞(如果有必要的話),直至計(jì)數(shù)器大于零,然后線程會(huì)減少這個(gè)計(jì)數(shù)。

在GCD中有三個(gè)函數(shù)是semaphore的操作,分別是:

dispatch_semaphore_create   創(chuàng)建一個(gè)semaphore
dispatch_semaphore_signal   發(fā)送一個(gè)信號(hào)
dispatch_semaphore_wait    等待信號(hào)
 
第一個(gè)函數(shù)有一個(gè)整形的參數(shù),我們可以理解為信號(hào)的總量;
dispatch_semaphore_signal是發(fā)送一個(gè)信號(hào),自然會(huì)讓信號(hào)總量+1,
dispatch_semaphore_wait等待信號(hào),當(dāng)信號(hào)總量少于0的時(shí)候就會(huì)一直等待,否則就可以正常的執(zhí)行,并讓信號(hào)總量-1,

特別說(shuō)明下:信號(hào)總量為0時(shí)dispatch_semaphore_wait會(huì)阻塞當(dāng)前的線程(主線程、其他線程),被阻塞的線程中無(wú)法執(zhí)行任何代碼。
根據(jù)這樣的原理,我們便可以快速的創(chuàng)建一個(gè)并發(fā)控制來(lái)同步任務(wù)和有限資源訪問(wèn)控制。

使用GCD的信號(hào)量實(shí)現(xiàn)并發(fā)的控制

創(chuàng)建了一個(gè)初使值為10的semaphore,每一次for循環(huán)都會(huì)創(chuàng)建一個(gè)新的線程,線程結(jié)束的時(shí)候會(huì)發(fā)送一個(gè)信號(hào),線程創(chuàng)建之前會(huì)信號(hào)等待,所以當(dāng)同時(shí)創(chuàng)建了10個(gè)線程之后,for循環(huán)就會(huì)阻塞,等待有線程結(jié)束之后會(huì)增加一個(gè)信號(hào)才繼續(xù)執(zhí)行,如此就形成了對(duì)并發(fā)的控制,如上就是一個(gè)并發(fā)數(shù)為10的一個(gè)線程隊(duì)列。

GCD執(zhí)行任務(wù)的其他一些常用方法

#重復(fù)執(zhí)行某個(gè)任務(wù),但是注意這個(gè)方法沒(méi)有辦法異步執(zhí)行(為了不阻塞線程可以使用dispatch_async()包裝一下再執(zhí)行)。 
dispatch_apply():
#單次執(zhí)行一個(gè)任務(wù),此方法中的任務(wù)只會(huì)執(zhí)行一次,重復(fù)調(diào)用也沒(méi)辦法重復(fù)執(zhí)行(單例模式中常用此方法)。 
dispatch_once():
#延遲一定的時(shí)間后執(zhí)行。 
dispatch_time():
#使用此方法創(chuàng)建的任務(wù)首先會(huì)查看隊(duì)列中有沒(méi)有別的任務(wù)要執(zhí)行,如果有,則會(huì)等待已有任務(wù)執(zhí)行完畢再執(zhí)行;同時(shí)在此方法后添加的任務(wù)必須等待此方法中任務(wù)執(zhí)行后才能執(zhí)行。(利用這個(gè)方法可以控制執(zhí)行順序,例如前面先加載最后一張圖片的需求就可以先使用這個(gè)方法將最后一張圖片加載的操作添加到隊(duì)列,然后調(diào)用dispatch_async()添加其他圖片加載任務(wù))
dispatch_barrier_async(): 
#實(shí)現(xiàn)對(duì)任務(wù)分組管理,如果一組任務(wù)全部完成可以通過(guò)
dispatch_group_async(): 
#方法獲得完成通知(需要定義dispatch_group_t作為分組標(biāo)識(shí))。       
dispatch_group_notify()

一個(gè)栗子:多個(gè)并發(fā)網(wǎng)絡(luò)請(qǐng)求完成后執(zhí)行下一步

  • 1.使用GCD的dispatch_group_t
    -(void)Btn2{
    
      NSString *str = @"http://www.lxweimin.com/p/6930f335adba";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_group_t downloadGroup = dispatch_group_create();
    for (int i=0; i<10; i++) {
      dispatch_group_enter(downloadGroup);
      NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
          NSLog(@"%d---%d",i,i);
          dispatch_group_leave(downloadGroup);
      }];
      [task resume];
     }
    dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
            NSLog(@"end");
      });
     }
    

    創(chuàng)建一個(gè)dispatch_group_t, 每次網(wǎng)絡(luò)請(qǐng)求前先dispatch_group_enter,請(qǐng)求回調(diào)后再dispatch_group_leave,對(duì)于enter和leave必須配合使用,有幾次enter就要有幾次leave,否則group會(huì)一直存在。當(dāng)所有enter的block都leave后,會(huì)執(zhí)行dispatch_group_notify的block。

  • 2.使用GCD的信號(hào)量dispatch_semaphore_t
    -(void)Btn3{
      NSString *str = @"http://www.lxweimin.com/p/6930f335adba";
      NSURL *url = [NSURL URLWithString:str];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      NSURLSession *session = [NSURLSession sharedSession];
    
      dispatch_semaphore_t sem = dispatch_semaphore_create(0);
      for (int i=0; i<10; i++) {
      NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
          NSLog(@"%@",[NSThread currentThread])
          NSLog(@"%d---%d",i,i);
          count++;
          if (count==10) {
              dispatch_semaphore_signal(sem);
              count = 0;
            } 
        }];
        [task resume];
     }
      dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
      dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"end");
      });
    }
    

    開(kāi)始信號(hào)量為0,等待,等10個(gè)網(wǎng)絡(luò)請(qǐng)求都完成了,dispatch_semaphore_signal(semaphore)為計(jì)數(shù)+1,然后計(jì)數(shù)-1返回,程序繼續(xù)執(zhí)行。

    這里特別說(shuō)一下,例子中的NSURLSessionDataTask 的block 回調(diào)中不是主線程,而是多線程環(huán)境。此時(shí)的主線程已經(jīng)被阻塞了,是不會(huì)執(zhí)行任何代碼的,只有在子線程中把信號(hào)量加1,才能結(jié)束主線程的阻塞。

    10個(gè)網(wǎng)絡(luò)請(qǐng)求順序回調(diào)。

    - (void)toCrashing
    {
        NSString *str = @"http://www.lxweimin.com/p/6930f335adba";
      NSURL *url = [NSURL URLWithString:str];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      NSURLSession *session = [NSURLSession sharedSession];
      
      NSConditionLock  *lock = [[NSConditionLock alloc] initWithCondition:0];
      dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
      for (int i=0; i<10; i++) {
          NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
              dispatch_async(queue, ^{
                  [lock lockWhenCondition:i];
                  NSLog(@"%d---%d",i,i);
                  [lock unlockWithCondition:i+1];
              });
          }];
          [task resume];
      }
     }
    

    使用NSConditionLock 可以解決。

小結(jié)

GCD的知識(shí)很多,本文就不一一羅列了,后續(xù)如有新的收獲,會(huì)持續(xù)更新的。


本文參考文章:
iOS編程中throttle那些事
關(guān)于iOS多線程,你看我就夠了
GCD入門(mén)(二): 多核心的性能

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

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

  • 最近頗花了一番功夫把多線程GCD人的一些用法總結(jié)出來(lái),一來(lái)幫自己鞏固一下知識(shí)、二來(lái)希望能幫到對(duì)這一塊還迷茫...
    人活一世閱讀 293評(píng)論 1 1
  • 目錄:iOS多線程(一)--pthread、NSThreadiOS多線程(二)--GCD詳解iOS多線程(三)--...
    Claire_wu閱讀 1,086評(píng)論 0 6
  • 目錄 一、基本概念1.多線程2.串行和并行, 并發(fā)3.隊(duì)列與任務(wù)4.同步與異步5.線程狀態(tài)6.多線程方案 二、GC...
    BohrIsLay閱讀 1,604評(píng)論 5 12
  • 參考:GCD源碼深入理解 GCDiOS多線程--徹底學(xué)會(huì)多線程之『GCD』關(guān)于iOS多線程,我說(shuō),你聽(tīng),沒(méi)準(zhǔn)你就懂...
    啊哈呵閱讀 2,893評(píng)論 2 2
  • 你總是碌碌無(wú)為,不求上進(jìn)。不去尋找讓自己發(fā)光發(fā)亮的可能,就只是一昧的抱怨命運(yùn)的不公,那么你本來(lái)就不值得成功。
    喵了個(gè)嗚的咪閱讀 225評(píng)論 0 0