日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

ios筆記-- 多線程應(yīng)該知道的那幾件事 GCD NSThr

系統(tǒng) 2556 0

iphone5s 出來了,CPU 升級(jí)到了64位 可以應(yīng)用到更大的內(nèi)存了,同時(shí)對(duì)多線程的處理吞吐能力也教之前提升了十幾倍。下面著中總結(jié)下ios 下多線程的知識(shí)點(diǎn)

ios筆記-- 多線程應(yīng)該知道的那幾件事 GCD NSThread NSOperation

1:現(xiàn)有的幾種多線程

概念 應(yīng)用場景
NSThread 蘋果公司的Cocoa框架共支持三種多線程機(jī)制,分別為NSThread、GCD(Grand Central Dispatch)、Cocoa NSOperatio。NSThree是官方推薦的線程處理方式,它在處理機(jī)制上,需要開發(fā)者負(fù)責(zé)手動(dòng)管理Thread的生命周期,包括子線程與主線程之間的同步等。線程共享同一應(yīng)用程序的部分內(nèi)存空間,它們擁有對(duì)數(shù)據(jù)相同的訪問權(quán)限。你得協(xié)調(diào)多個(gè)線程 對(duì)同一數(shù)據(jù)的訪問,一般做法是在訪問之前加鎖,這會(huì)導(dǎo)致一定的性能開銷。在 iOS 中我們可以使用多種形式的 thread。 比其他兩個(gè)輕量級(jí) 需要自己管理線程的生命周期,線程同步。 線程同步對(duì)數(shù)據(jù)的加鎖會(huì)有一定的系統(tǒng)開銷
NSOperation 如果需要讓線程同時(shí)并行運(yùn)行多個(gè),可以將線程加入隊(duì)列(Queue)中,NSOperationQueue類就是一個(gè)線程隊(duì)列管理類,他提供了線程并行、隊(duì)列的管理。可以認(rèn)為NSOperationQueue就是一個(gè)線程管理器,通過addOperations方法,我們可以一次性把多個(gè)(數(shù)組形式)線程添加到隊(duì)列中。同時(shí),NSOperationQueue允許通過setMaxConcurrentOperationCount方法設(shè)置隊(duì)列的并行(同一時(shí)間)運(yùn)行數(shù)量
GCD Grand Central Dispatch (GCD)是Apple開發(fā)的一個(gè)多核編程的解決方法。該方法在Mac OS X 10.6雪豹中首次推出,并隨后被引入到了iOS4.0中。GCD是一個(gè)替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術(shù)的很高效和強(qiáng)大的技術(shù),它看起來象就其它語言的閉包(Closure)一樣,但蘋果把它叫做blocks。

一般移動(dòng)平臺(tái)上系統(tǒng)都會(huì)有一個(gè)專門的檢查機(jī)制,看程序有沒有很長時(shí)間被阻塞住,沒有回來檢查主消息隊(duì)列。發(fā)現(xiàn)這種情況一般都是把程 序作為“無響應(yīng)”干掉。iOS一般情況下是10秒為上限。10秒內(nèi)程序沒有回到主消息循環(huán)就被干掉。在前臺(tái)后臺(tái)切換時(shí)更嚴(yán)格,大概是5秒左右。 注釋1

2:簡單的Demo

因?yàn)镚CD 是應(yīng)用最廣的 而且也是蘋果現(xiàn)在極力鼓動(dòng)開發(fā)者應(yīng)用的 所以NSThread NSOperation 只做簡單應(yīng)用

1:NSThread

1.1 NSThread 有兩種直接創(chuàng)建方式:

第一個(gè)是實(shí)例方法--直接創(chuàng)建線程并且開始運(yùn)行線程

  • (id)initWithTarget:(id)target selector:(SEL)selector object:(id)

第二個(gè)是類方法--先創(chuàng)建線程對(duì)象,然后再運(yùn)行線程操作,在運(yùn)行線程操作前可以設(shè)置線程的優(yōu)先級(jí)等線程信息

  • (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

selector :線程執(zhí)行的方法,這個(gè)selector只能有一個(gè)參數(shù),而且不能有返回值。
target :selector消息發(fā)送的對(duì)象
argument :傳輸給target的唯一參數(shù),也可以是nil

1.2線程間通信

a 在應(yīng)用程序主線程中做事情:

      
        performSelectorOnMainThread:
      
      
        withObject:
      
      
        waitUntilDone:
      
      
        performSelectorOnMainThread:
      
      
        withObject:
      
      
        waitUntilDone:
      
      
        modes:
      
    

b 在指定線程中做事情:

      
        performSelector:
      
      
        onThread:
      
      
        withObject:
      
      
        waitUntilDone:
      
      
        performSelector:
      
      
        onThread:
      
      
        withObject:
      
      
        waitUntilDone:
      
      
        modes:
      
    

c 在當(dāng)前線程中做事情:

      
        performSelector:
      
      
        withObject:
      
      
        afterDelay:
      
      
        performSelector:
      
      
        withObject:
      
      
        afterDelay:
      
      
        inModes:
      
    

d 取消發(fā)送給當(dāng)前線程的某個(gè)消息

      
        cancelPreviousPerformRequestsWithTarget:
      
      
        cancelPreviousPerformRequestsWithTarget:
      
      
        selector:
      
      
        object:
      
    

2:NSOperation

首先是建立NSOperationQueue和NSOperations。NSOperationQueue會(huì)建立一個(gè)線程管理器,每個(gè)加入到線程operation會(huì)有序的執(zhí)行。

      NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = 
      
        [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doWork:) object:someObject]; 
[queue addObject:operation]; 
[operation release];

      
    

使用NSOperationQueue的過程:
1. 建立一個(gè)NSOperationQueue的對(duì)象
2. 建立一個(gè)NSOperation的對(duì)象
3. 將operation加入到NSOperationQueue中
4. release掉operation

NSInvocationOperation,NSInvocationOperation是NSOperation的子類,允許運(yùn)行在operation中的targer和selector

3:多線程互斥同步問題

注釋2

在iOS中有幾種方法來解決多線程訪問同一個(gè)內(nèi)存地址的互斥同步問題:

  • 方法一,@synchronized(id anObject),(最簡單的方法) 會(huì)自動(dòng)對(duì)參數(shù)對(duì)象加鎖,保證臨界區(qū)內(nèi)的代碼線程安全
      @
      
        synchronized
      
      (
      
        self
      
      ) {
        
      
        // 這段代碼對(duì)其他 @synchronized(self) 都是互斥的
      
      
        // self 指向同一個(gè)對(duì)象
      
      
}

    
  • 方法二,NSLock

NSLock對(duì)象實(shí)現(xiàn)了NSLocking protocol,包含幾個(gè)方法: lock,加鎖 unlock,解鎖 tryLock,嘗試加鎖,如果失敗了,并不會(huì)阻塞線程,只是立即返回NO lockBeforeDate:,在指定的date之前暫時(shí)阻塞線程(如果沒有獲取鎖的話),如果到期還沒有獲取鎖,則線程被喚醒,函數(shù)立即返回NO 比如 : NSLock *theLock = [[NSLock alloc] init];

      
      
        if ([the
        
          
            Lock
          
          
            lock
          
          ]) {

//
          
            do
          
           something here

[theLock unlock];
        
         

} 

      
  • 方法三,NSRecursiveLock,遞歸鎖

NSRecursiveLock,多次調(diào)用不會(huì)阻塞已獲取該鎖的線程。

      
      
        NSRecursiveLock *theLock = 
        
          [[NSRecursiveLock alloc] init]; 
void MyRecursiveFunction(int value) { 
    [theLock lock]; 
    if (value != 0) { 
        –value; 
        MyRecursiveFunction(value); 
    }
    [theLock unlock]; 
} 
MyRecursiveFunction(5);

        
      
  • 方法四,NSConditionLock,條件鎖

NSConditionLock,條件鎖,可以設(shè)置條件

      
      
        //公共部分
id condLock = 
        
          [[NSConditionLock alloc] initWithCondition:NO_DATA]; 

//線程一,生產(chǎn)者
while(true) { 

[condLock lockWhenCondition:NO_DATA]; 

//生產(chǎn)數(shù)據(jù)
[condLock unlockWithCondition:HAS_DATA];

}

//線程二,消費(fèi)者
while (true) { 

[condLock lockWhenCondition:HAS_DATA

//消費(fèi)
[condLock unlockWithCondition:NO_DATA]; 
}

        
      
  • 方法五,NSDistributedLock,分布鎖

NSDistributedLock,分布鎖,文件方式實(shí)現(xiàn),可以跨進(jìn)程 用tryLock方法獲取鎖。 用unlock方法釋放鎖。 如果一個(gè)獲取鎖的進(jìn)程在釋放鎖之前掛了,那么鎖就一直得不到釋放了,此時(shí)可以通過breakLock強(qiáng)行獲取鎖。

本章節(jié)(多線程互斥同步問題)參考自: http://blog.sina.com.cn/s/blog_72819b170101590n.html

3:GCD多線程互斥同步問題(阻塞線程的方式去實(shí)現(xiàn)同步)

注釋3

1.串行隊(duì)列

(1)GCD下的dispatch_queue隊(duì)列都是FIFO隊(duì)列,都會(huì)按照提交到隊(duì)列的順序執(zhí)行. 只是根據(jù)隊(duì)列的性質(zhì),分為

<1>串行隊(duì)列:用戶隊(duì)列、主線程隊(duì)列

<2>并行隊(duì)列.

(2)同步(dispatch_sync)、異步方式(dispatch_async). 配合串行隊(duì)列和并行隊(duì)列使用.
同步隊(duì)列直接提交兩個(gè)任務(wù)就可以. // 串形隊(duì)列 dispatch_queue_t serilQueue = dispatch_queue_create("com.quains.myQueue", 0);

      
      
        
          //開始時(shí)間
        
        
          NSDate
        
         *startTime = [
        
          NSDate
        
         date];


__block 
        
          UIImage
        
         *image = 
        
          nil
        
        ;


        
          //1.先去網(wǎng)上下載圖片
        
        
          dispatch_async
        
        (serilQueue, ^{
   
        
          //下載圖片
        
        
});


        
          //2.在主線程展示到界面里
        
        
          dispatch_async
        
        (serilQueue, ^{

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

    
        
          // 在主線程展示
        
        
          dispatch_async
        
        (dispatch_get_main_queue(), ^{
      
        
          //顯示圖片
        
        
});


        
          //3.清理
        
        
dispatch_release(serilQueue);
[image release];

      

注意:

(1) __block變量分配在棧,retain下,防止被回收.

(2)dispatch要手動(dòng)create和release.

(3)提交到主線程隊(duì)列的時(shí)候,慎用同步dispatch_sync方法,有可能造成死鎖. 因?yàn)橹骶€程隊(duì)列是串行隊(duì)列,要等隊(duì)列里的任務(wù)一個(gè)一個(gè)執(zhí)行.所以提交一個(gè)任務(wù)到隊(duì)列,如果用同步方法就會(huì)阻塞住主線程,而主線程又要等主線程隊(duì)列里的任務(wù)都執(zhí)行完才能執(zhí)行那個(gè)剛提交的,所以主線程隊(duì)列里還有其他的任務(wù)的話,但他已經(jīng)被阻塞住了,沒法先完成隊(duì)列里的其他任務(wù),即,最后一個(gè)任務(wù)也沒機(jī)會(huì)執(zhí)行到,于是造成死鎖.

(4)提交到串行隊(duì)列可以用同步方式,也可以用異步方式.

2.并行隊(duì)列

采用并行隊(duì)列的時(shí)候,可以采用同步的方式把任務(wù)提交到隊(duì)列里去,即可以實(shí)現(xiàn)同步的方式

//新建一個(gè)隊(duì)列 dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

      
      
        
          //記時(shí)
        
        
          NSDate
        
         *startTime = [
        
          NSDate
        
         date];


        
          //加入隊(duì)列
        
        
          dispatch_async
        
        (concurrentQueue, ^{
    __block 
        
          UIImage
        
         *image = 
        
          nil
        
        ;

    
        
          //1.先去網(wǎng)上下載圖片
        
        
          dispatch_sync
        
        (concurrentQueue, ^{
        
        
          //下載圖片
        
        
    });

    
        
          //2.在主線程展示到界面里
        
        
          dispatch_sync
        
        (dispatch_get_main_queue(), ^{
        
        
          //顯示圖片
        
        
    });
});

      

兩個(gè)同步的任務(wù)用一個(gè)異步的包起來,提交到并行隊(duì)列里去,即可實(shí)現(xiàn)同步的方式.

3.使用分組方式

group本身是將幾個(gè)有關(guān)聯(lián)的任務(wù)組合起來,然后提供給開發(fā)者一個(gè)知道這個(gè)group結(jié)束的點(diǎn). 雖然這個(gè)只有一個(gè)任務(wù),但是可以利用group的結(jié)束點(diǎn),去阻塞線程,從而來實(shí)現(xiàn)同步方式.

例如讓后臺(tái)2個(gè)線程并行執(zhí)行,然后等2個(gè)線程都結(jié)束后,再匯總執(zhí)行結(jié)果。這個(gè)可以用dispatch_group, dispatch_group_async 和 dispatch_group_notify來實(shí)現(xiàn),示例如下:

       dispatch_group_t 
      
        group
      
       = dispatch_group_create();
 dispatch_group_async(
      
        group
      
      , dispatch_get_global_queue(
      
        0
      
      ,
      
        0
      
      ), ^{
      
      
        // 并行執(zhí)行的線程一
      
      
 });
 dispatch_group_async(
      
        group
      
      , dispatch_get_global_queue(
      
        0
      
      ,
      
        0
      
      ), ^{
      
      
        // 并行執(zhí)行的線程二
      
      
 });
 dispatch_group_notify(
      
        group
      
      , dispatch_get_global_queue(
      
        0
      
      ,
      
        0
      
      ), ^{
      
      
        // 匯總結(jié)果
      
      
 });

    
      
      
        dispatch_group_t 
        
          group
        
         = dispatch_group_create();

dispatch_queue_t queue = dispatch_get_global_queue(
        
          0
        
        , 
        
          0
        
        );

NSDate 
        
          *startTime
        
         = [NSDate 
        
          date
        
        ];

__block UIImage 
        
          *image
        
         = nil;

dispatch_group_async(
        
          group
        
        , queue, ^{
    
        
          //1.先去網(wǎng)上下載圖片
        
        
    });


        
          // 2.等下載好了再在刷新主線程
        
        
dispatch_group_notify(
        
          group
        
        , queue, ^{

    
        
          //在主線程展示到界面里
        
        
    dispatch_async(dispatch_get_main_queue(), ^{
     
        
          //顯示圖片
        
        
    });

});


        
          // 釋放掉
        
        
dispatch_release(
        
          group
        
        );

      

dispatch_group 也要手動(dòng)創(chuàng)建和釋放. dispatch_notify()提供了一個(gè)知道group什么時(shí)候結(jié)束的點(diǎn). 當(dāng)然也可以使用dispatch_wait()去阻塞

4.信號(hào)量

信號(hào)量 和 瑣 的作用差不多,可以用來實(shí)現(xiàn)同步的方式. 但是信號(hào)量通常用在 允許幾個(gè)線程同時(shí)訪問一個(gè)資源,通過信號(hào)量來控制訪問的線程個(gè)數(shù).

// 信號(hào)量初始化為1 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

      
      
        
          dispatch_queue_t
        
         queue = dispatch_get_global_queue(
        
          0
        
        , 
        
          0
        
        );


        
          NSDate
        
         *startTime = [
        
          NSDate
        
         date];

__block 
        
          UIImage
        
         *image = 
        
          nil
        
        ;



        
          //1.先去網(wǎng)上下載圖片
        
        
          dispatch_async
        
        (queue, ^{

    
        
          // wait操作-1
        
        
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
        
          // 開始下載
        
        
          // signal操作+1
        
        
    dispatch_semaphore_signal(semaphore);
});



        
          // 2.等下載好了再在刷新主線程
        
        
          dispatch_async
        
        (dispatch_get_main_queue(), ^{

    
        
          // wait操作-1
        
        
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
        
          //顯示圖片
        
        
          // signal操作+1
        
        
    dispatch_semaphore_signal(semaphore);
});

      

dispatch_wait會(huì)阻塞線程并且檢測信號(hào)量的值,直到信號(hào)量值大于0才會(huì)開始往下執(zhí)行,同時(shí)對(duì)信號(hào)量執(zhí)行-1操作.
dispatch_signal則是+1操作.

3.后臺(tái)運(yùn)行

GCD的另一個(gè)用處是可以讓程序在后臺(tái)較長久的運(yùn)行。在沒有使用GCD時(shí),當(dāng)app被按home鍵退出后,app僅有最多5秒鐘的時(shí)候做一些保存或清理資源的工作。但是在使用GCD后,app最多有10分鐘的時(shí)間在后臺(tái)長久運(yùn)行。這個(gè)時(shí)間可以用來做清理本地緩存,發(fā)送統(tǒng)計(jì)數(shù)據(jù)等工作。

讓程序在后臺(tái)長久運(yùn)行的示例代碼如下:

      
        // AppDelegate.h文件
      
      
@
      
        property
      
       (
      
        assign
      
      , 
      
        nonatomic
      
      ) UIBackgroundTaskIdentifier backgroundUpdateTask;


      
        // AppDelegate.m文件
      
      
- (
      
        void
      
      )applicationDidEnterBackground:(
      
        UIApplication
      
       *)application
{
    [
      
        self
      
       beingBackgroundUpdateTask];
    
      
        // 在這里加上你需要長久運(yùn)行的代碼
      
      
    [
      
        self
      
       endBackgroundUpdateTask];
}

- (
      
        void
      
      )beingBackgroundUpdateTask
{
    
      
        self
      
      
        .backgroundUpdateTask
      
       = [[
      
        UIApplication
      
       sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [
      
        self
      
       endBackgroundUpdateTask];
    }];
}

- (
      
        void
      
      )endBackgroundUpdateTask
{
    [[
      
        UIApplication
      
       sharedApplication] endBackgroundTask: 
      
        self
      
      
        .backgroundUpdateTask
      
      ];
    
      
        self
      
      
        .backgroundUpdateTask
      
       = UIBackgroundTaskInvalid;
}

    

[1] http://www.cnblogs.com/linyawen/archive/2012/07/24/2606709.html

[2] http://www.cnblogs.com/Quains/archive/2013/07/10/3182823.html

[3] http://blog.devtang.com/blog/2012/02/22/use-gcd/


另外 本人打算十一后離職換份工作,哪位仁兄公司有意向 站內(nèi)信聯(lián)系,幫忙內(nèi)推下哈.

再打下廣告哈 我搭建的個(gè)人博客 也已經(jīng)上線了 引用的是hexo , 地址是 hufeng825.github.com ui配色再微調(diào)中,對(duì)ie10 以下支持不太好 建議用chrome Firefox 或者safrari 瀏覽 另外也已經(jīng)對(duì)移動(dòng)設(shè)備做了響應(yīng)是布局.



ios筆記-- 多線程應(yīng)該知道的那幾件事 GCD NSThread NSOperation


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 鄄城县| 威宁| 海淀区| 隆尧县| 隆昌县| 台山市| 云和县| 商城县| 龙井市| 衡山县| 保靖县| 黔南| 大新县| 修文县| 安仁县| 德钦县| 金堂县| 宁波市| 木里| 邵阳市| 米脂县| 百色市| 阿克陶县| 台北县| 麦盖提县| 巴林左旗| 剑川县| 新源县| 惠来县| 夏邑县| 舒城县| 荆门市| 中宁县| 双桥区| 历史| 综艺| 嵊州市| 威海市| 房山区| 富民县| 庆阳市|