IOS線程的一些總結

 

主線程的做用 (在主線程中才能設置)ios

顯示/刷新UI界面程序員

處理UI事件(好比點擊事件、滾動事件、拖拽事件);編程

 

主線程的使用注意安全

別將比較耗時的操做放到主線程中。多線程

耗時操做會卡住主線程。影響體驗。併發

[NSThread currentThread]得到當前線程。app

打印線程。num屬性顯示有多少條線程。異步

 

將耗時操做放在子線程中(後臺線程,非主線程);async

多線程好處在哪?函數

在用戶點擊按鈕那一刻就有反應

能同時處理耗時操做和用UI控件的事件。

多線程技術:

1,pthread    一套通用的多線程API(幾乎不用)

適用於Unix\Linux\Windows等系統

跨平臺\可移植

使用難度大。

須要程序員來管理線程的生命週期。

建立一個線程用

 

pthread_create(&pthread_t,NULL,(void *)(*)(void *),NULL);便可

 

2,NSThread  使用OC,(程序員管理)

使用更加面向對象

簡單易用,可直接操做線程對象

建立一個線程用 [NSThread alloc] init……

[self start] 開啓;

selector(mainThread) 返回主線程;

selector(isMainThread) 是不是主線程;

selector (currentThread); 判斷當前線程;

能夠設置線程優先級, 

優先級越高,CUP的佔有率越高。

線程有name屬性,能夠設置名字。

建立線程第2種方式:

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

分離一條線程,沒有返回值。

 建立線程第3種方式。

[self performSelectorInBackground:@selector(run:) withObject:@"abc參數"];

 

 每個時刻只有一個線程在執行。

[thread start]後進入一個可調度線程池(有機會被調度。狀態爲就緒或運行);

          start

new  ----》 就緒  -----》運行

                             《------

調用了sleep方法或等待同步鎖 後就進入  阻塞狀態(清出線程池)  條件知足後又回到調度池。

調用stop 線程進入的是dead 死亡狀態。再也沒有了。

+(void)sleepUntilDate:(NSDate *)date;

+(void) sleepForTimeInterval:(NSTimeInterval)ti; 

 

線程運行完以後就會死亡, 不能能再次調用。

[thread exit]線程退出。 

 

3,GCD   C

旨在替代NSThread等線程技術

充分利用設備的多核。(自動)

不用管理線程。

GCD有2個核心概念

任務:執行什麼樣的操做。

隊列:用來存聽任務。

GCD的使用就2個步驟。

定製任務

確認想作的事情。

將任務添加到隊列中

GCD會自動將隊列中的任務取出,放到對應的線程中執行。

任務取出遵循隊列的FIFO原則,先進先出。後進後出

調用libdispach庫才行

都是懿dispatch開頭。

 

1,用同步的方式來執行任務。(有順序執行)

dispatch_sync(queue,block);同步執行

queue:隊列

block:任務

2,用異步的方式執行任務(在另外一條線程中執行)

dispatch_async(queue,block);

GCD隊列分2大類;

併發隊列;

可讓任務同時執行。

串行隊列

用函數給隊列賦值任務;

隊列分爲並行和串行。

函數分爲同步和異步。

異步函數加並行隊列  == 開一條子線程。

同步:在當前線程中執行任務,不具有開啓新線程能力

異步:在新的線程中執行任務,具有開啓新線程的能力。

 

併發和串行決定了任務的執行方式。

 

併發:多個任務併發執行。  調用dispatch_queue_t queue = dispatch_get_global_queue(優先級,隨意值);

添加任務到隊列中,執行任務。

 

 

串行:一個任務執行完畢後,再執行下一個任務。

serial 英文,連續,串行的意思。。

dispatch_queue_t queue = dispatch_queue_create("com.itheima,queue",隊列的類型);

隊列名稱在調試的時候能夠看的到代碼在哪一個隊列裏面執行。

 

調用async函數會開啓一個線程,可是若是函數的隊列是串行的就不會開更多了。每加一個並行隊列開啓線程數會加1.

調用sync函數不會開線程。並行和串行隊列都同樣

 MRC裏面釋放用dispatch_release(queue);

ARC裏面不能用,會自動釋放。

 

即便在ARC中

凡是函數名中帶有create\copy\new\retain等字眼返回值的,都須要在不使用這個數據的時候進行release(有的話都寫一下,報錯就不寫了)

GCD數據類型則不用,release。  

CF(Core foundation)的數據類型在ARC環境下仍是得須要再作release;

系統自帶的用get ,本身創的用create 。(蘋果規範);

主線程隊列是不會開新線程的。

 別在主線程中用同步函數添加主隊列,會造成相互等待,死鎖。

用異步函數能夠(異步能夠延緩執行,同步要立刻執行)。

同步會在當前進程中執行,會停下來。異步會本身開一個線程。與當前線程併發執行,(只要隊列不是主隊列)

 

iOS常見的延時執行有2種方式;

1,[self performSelector:@selector(run)  withObject:nil afterDelay:2.0];

2秒以後調用run方法;

2,GCD方式

dispatch_after();//有個隊列參數,表示多少秒後在哪一個線程中執行。

     //1.聲明在哪一個隊列

     dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.計算任務執行的時間

    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));

     // 3.會在when這個時間點, 執行queue中的任務

    dispatch_after(when, queue, ^{        //會另外聲明一個隊列。

        NSLog(@"----run----%@", [NSThread currentThread]);

    });

須要整個程序執行過程當中只能打印一次時。

static dispatch_once_t onceToken;

能夠用 dispatch_once(&onceToken,^{

    NSLog(@"--------touchesBegin");

});

 

隊列組,:

有這麼一種需求。

等2個線程都執行完以後再到主線程中執行操做。

就能夠用隊列組把2個線程封裝。執行隊列組。   

 

建立group//比串行執行要快不少。。。

    dispatch_group_t group = dispatch_group_create();

 建立隊列

   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

 把任務和隊列放到異步組函數中

  */

    dispatch_group_async(group, queue, ^{

        for (int i=0; i<100; i++) {

            NSLog(@"執行線程一:%d",i);

        }

    });

    

    dispatch_group_async(group, queue, ^{

        for (int i=0; i<100; i++) {

            NSLog(@"執行線程二:%d",i);

        }

    });

//線程組執行完成後執行:(重點,沒有它,要組也沒啥用了)

 dispatch_group_notify(group, queue, ^{

        NSLog(@"線程組執行完成");

    });

 //下面是重複執行:10表明重複執行次數。中間是執行隊列。index是第幾回執行;(注意執行是併發(這是與for循環的區別));

    dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {

        //index表示是第幾回執行

        NSLog(@"執行第%zu次",index);

        

    });

 

柵欄barrier ,用來將線程分開,執行完上面的線程到執行它再到執行後面的線程;(有隊列queue關鍵字,因此就是把queue隊列的隔開,其它隊列可不行,中間執行)

dispatch_barrier_async(queue, ^{

        NSLog(@"barrier");

    });

 

 

 

4,NSOperation  OC

基於GCD

比GCD多了一些簡單實用的功能

使用更加面向對帶的用get ,本身創的用create 。(蘋果規範);

, 配合使用NSOperation NSOperationQueue也能實現多線程編程

,NSOperation和NSOperationQueue 實現多線程的具體步驟

先將須要執行的操做封裝到一個NSOperation 對象中。

而後將NSOperation對象添加到NSOperationQueue中

系統會自動將NSOperationQueue中的NSOperation取出來

將取出的NSOperation封裝的操做放到一條新線程中執行。

NSOperation是一個抽象類,並不具有封裝操做的能力,必須使用它的子類。

 

使用NSOperation子類的方式有3種。

NSInvocationOperation

NSBlockOperation

自定義的子類繼承NSOperation,實現內部相應的方法。

 

NSInvocationOperation  

建立操做對象,封裝要執行的任務。

NSInvocationOperation * operation = [  alloc]  initwithTarget……   任務是方法;

能夠[operation start]調用,可是這樣是會在當前線程中調用,並沒有啥用,仍是得放到方法中去;

NSBlockOperation

使用類方法來聲明

NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock^{   }];   任務是block ,NSBlockOperation 是block的封裝

也能夠  直接用start 調用,但也無啥用。

有方法:  [operation addExecutionBlock:^{

     NSLog(@"%@",[NSThread currentThread]);

}];

只要operation封裝的任務大於1,就會異步執行。

調用了addExecutionBlock 的話 operation的任務就有多個。   用start是會多線程執行的。

 

-(void) invocationOperation

{

        

}

NSOperatinQueue * queue =[ [NSOperationQueue alloc] init];

[queue addOperation:operation1];

[queue addOperation:operation2];//這樣直接就會是異步執行。   (併發有着不肯定性。可是機率是會有的)

 

隊列能夠設置 最大併發數,  queue.maxConcurrentOperationCount = 1;  表示在這個隊列中最多同時執行的併發任務數爲1;

(不要設置太多,否則可能會卡, 2-3就好,5之內,否則UI會卡);

- (void) cancelAllOperations; 隊列的所有線程都停掉

也能夠調用NSOperation 的-(void)cancel 方法取消單個操做。

-(void)setSuspended:(BOOL)b;//YES 表明暫停隊列

 

//(一個比較好的地方是 : cancel表明取消的意思,suspended,表示已經掛起,這些英文記住了用來命名挺好的,看看別人的過去時都是加ed的,就是這麼強,因此語法很差的話,多關注ios的命名規則時很好的);

 

當下載時,同時開啓多條子線程,當用戶操做UI時會發生卡頓現象,那麼咱們就能夠在用戶滾動時掛起隊列。不操做時就繼續隊列/

下載時同時開啓多條線程下載會比較快。

 

有個有趣的地方是 NSOperation 竟然也有一個隊列優先級, 我了個去, 不愧是GCD的封裝啊 ,就是那麼強大。

 還能夠設置依賴。來保證執行的順序;

[operationB addDependency: operationA]; B依賴A  那麼B只能在A以後執行。(靈活應用能夠作不少事情。)

A-》B    B -》C   C—》A 

當心相互依賴問題。

 

 

能夠在不一樣的queue的NSOperation之間建立依賴關係。可是不能相互依賴。

 操做的監聽。

operation.completionBlock = ^{

   //下載完圖片後想作的事情。

};

 自定義Operation(繼承自Operation)

       要在operation裏面實現  -(void)main{}方法

 

 

多線程安全隱患:1,一塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一個資源

    好比說多個線程訪問同一個對象、同一個變量、同一個文件。

使用線程鎖來解決,同一時間只能有一個線程訪問。

相關文章
相關標籤/搜索