iOS-多線程之GCD(原創)

来源:http://www.cnblogs.com/start-ios/archive/2016/03/28/5328488.html
-Advertisement-
Play Games

前言 GCD 全稱 Grand Central DisPath NSOperation便是基於GCD的封裝 基礎知識 1.GCD的優勢 (1)為多核的並行運算提出瞭解決方案 (2)GCD會自動利用更多的CPU內核 比和雙核 四核 (3).GCD自動管理線程的生命周期(創建線程 調度任務 銷毀線程) ...


前言

GCD

全稱 Grand Central DisPath NSOperation便是基於GCD的封裝

 

基礎知識

1.GCD的優勢

 (1)為多核的並行運算提出瞭解決方案

 (2)GCD會自動利用更多的CPU內核 比和雙核 四核

 (3).GCD自動管理線程的生命周期(創建線程 調度任務 銷毀線程)

 (4).程式員只需告訴GCD想要執行什麼任務 不需要編寫任何線程管理代碼

 

 2.GCD中有2個核心概念

 任務: 執行什麼操作

 隊列: 用來存放任務

 

 3.隊列可以分為兩大類型

 串列隊列(Serial Dispatch Queue):只有一個線程,加入到隊列中的操作按添加順序依次執行,一個任務執行完畢後,才能再執行下一個任務。

 併發隊列(Concurrent Dispatch Queue):有多個線程,操作進來以後他會將這些線程安排在可用的處理器上,同時保證先進來的任務優先處理。

 其實在GCD中還有一個特殊隊列就是主隊列 主隊列中永遠只有一個線程-主線程 用來執行主線程的操作任務

 

 4.採用GCD做多線程 可以抽象分為二步

 (1)找到隊列(主隊列或串列隊列或並行隊列)

 (2)在隊列中用同步或者非同步的方式執行任務

 

 5.執行隊列中的任務的二種方式

 (1)同步 只能在當前線程執行任務 不具備開啟新線程的能力--主線程

 (2)非同步 可以在新的線程中執行任務 具備開啟新線程的能力--子線程

 

下麵介紹一下串列 並行 同步 非同步 

- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    // Do any additional setup after loading the view, typically from a nib.

#pragma mark ====串列同步====

    

//    //1.找到隊列 第一個參數:該隊列的名字 第二個參數:指定隊列的類型

//    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

//    //2.給隊列指定任務 第一個參數:任務在哪個隊列中執行 第二個參數:想要執行的操作

//    //asyn是非同步 syn是同步

//    dispatch_sync(serialQueue, ^{

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

//    });

//    

#pragma mark ====串列非同步====

//    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

//    dispatch_async(serialQueue, ^{

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

//    });

#pragma mark ====並行同步====

//    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

//    dispatch_sync(concurrentQueue, ^{

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

//    });

#pragma mark ====並行非同步====

        dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

        dispatch_async(concurrentQueue, ^{

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

        });

}

此時我們新建一個類來看一下 用GCD的形式來載入網路圖片讓它顯示在self.view上 我這裡為它命名為OneImageViewController  效果圖以及.m代碼如下

#import "OneImageViewController.h"
#define kurl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"
@interface OneImageViewController ()
{
    UIImageView *imageView;
}
@end

@implementation OneImageViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    /*
     1.創建視圖
     2.創建一個串列隊列
     3.用非同步方式執行隊列中的任務
     4.載入網路資源
     5.回到主線程 更新UI
     
     
     */
    //1.創建視圖
    imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
    [self.view addSubview:imageView];
    //2.創建一個串列隊列
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    //3.用非同步方式執行隊列中的任務
    dispatch_async(serialQueue, ^{
        //4.載入網路資源
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kurl]];
        UIImage *image = [UIImage imageWithData:data];
        //5.回到主線程 dispatch_get_main_queue這個函數 找到主隊列
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        dispatch_sync(mainQueue, ^{
           //6.更新UI
            imageView.image = image;
        });
        
    });


}
@end

  

利用GCD載入多張網路圖片 我在這裡給類命名為MoreImageViewViewController 效果圖以及.m代碼如下

 

#import "MoreImageViewViewController.h"
#define kurl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"
@interface MoreImageViewViewController ()
{
    int imageIndex;
    dispatch_queue_t concurrentQueue;
    
}
@end

@implementation MoreImageViewViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.edgesForExtendedLayout = UIRectEdgeNone;
    /*
     1.創建多個視圖
     2.找到並行隊列
     3.給這個並行隊列指定多個任務
     4.在子線程載入網路資源
     5.回到主線程
     6.更新UI
     */
    
    imageIndex = 100;
    
    //1.創建多個視圖
    for (int row = 0; row<3; row++) {
        for (int list = 0; list<2; list++) {
            
            UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10+list*200, 10+row*200, 180, 180)];
            
            //imageView.backgroundColor = [UIColor orangeColor];
            
             imageView.tag = imageIndex++;
            
            [self.view addSubview:imageView];
            
        }
    }
    //2.找到並行隊列 dispatch_get_global_queue 獲取到系統的全局併列隊列
    
    //第一個參數:是優先順序 第二個參數:保留參數 沒用
//    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0, 0);
    
      concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_SERIAL);
    
    //3.給這個並行隊列指定多個任務
    for (int index = 0; index<6; index++) {
        dispatch_async(concurrentQueue, ^{
            [NSThread sleepForTimeInterval:0.5];
            //4.載入網路資源
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kurl]];
            UIImage *image = [UIImage imageWithData:data];
            //5.回到主線程
            dispatch_sync(dispatch_get_main_queue(), ^{
                //6.更新UI
                UIImageView *imageView = [self.view viewWithTag:100+index];
                imageView.image = image;
            });

        });
    }
    
    [self controlBtn];
}

- (void)controlBtn{
    
    
    UISegmentedControl *segment = [[UISegmentedControl alloc]initWithItems:@[@"暫停",@"開啟",]];
    
    segment.frame = CGRectMake(50, 620, 300, 50);
    
    segment.apportionsSegmentWidthsByContent = YES;
    
    [self.view addSubview:segment];
    
    [segment addTarget:self action:@selector(clickSegment:) forControlEvents:UIControlEventValueChanged];
}

- (void)clickSegment:(UISegmentedControl *)sender {
    
    switch (sender.selectedSegmentIndex) {
            
        case 0:{
            //暫停隊列
            dispatch_suspend(concurrentQueue);
        }break;
            
        case 1:{
            //恢復隊列
            dispatch_resume(concurrentQueue);
            
        }break;
            
    }

 

開發中我們可能會用到線程鎖 比如購票搶票這一功能  

沒線程鎖的情況下: 我走進購票大廳,買票的人都沒有排隊,我好不容易擠到視窗前,正打算掏錢買票的時候,旁邊有人已經把錢給了售票員。雖然你的線程已經開始執行買票的方法,但當你去拿票時,也就是將票數減一時,CPU將你的線程給中斷,開始執行其他的線程,CPU返回繼續執行你的線程的時候,票已經沒了。

有線程鎖的情況下:* 我走進購票大廳,買票的人都在排隊,當我到櫃臺能保證我買票的關鍵過程,也就是報站、掏錢、拿票過程不受干擾,我採用線程鎖將這個關鍵過程給鎖起來,以保證我能順利的買到票。

我在這裡命名為GCDLockViewController 具體.m代碼如下

#import "GCDLockViewController.h"

@interface GCDLockViewController ()
{
    NSLock *mylock;
}
@end

@implementation GCDLockViewController
- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    //實例化一個線程鎖
    mylock = [NSLock new];
#pragma mark ====線程鎖====
    __block int ticketNum = 10;
    dispatch_queue_t concurrent = dispatch_get_global_queue(0, 0);
    for (int index = 0; index<15; index++) {
        dispatch_async(concurrent, ^{
            
//            [mylock lock];
//            if (ticketNum>0) {
//                ticketNum--;
//                NSLog(@"還剩%d張票",ticketNum);
//            }
//            [mylock unlock];
            //參數一般是self 與self相關的變數 多個線程同時同時只訪問一次
            @synchronized(self) {
                if (ticketNum>0) {
                                    ticketNum--;
                                    NSLog(@"還剩%d張票",ticketNum);
                                }

            }
            
            
            
        });
    }
    

}
@end

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這一篇主要來講一下自定義控制項中的自定義viewgroup,我們以項目中最常用的下拉刷新和載入更多組件為例 簡單介紹一下自定義viewgroup時應該怎麼做。 分析:下拉刷新和載入更多的原理和步驟 自定義一個viewgroup,將headerview、contentview和footerview從上到 ...
  • J2ObjC 是一個Google開發的開源工具,用於將Java代碼轉換為Objective-C代碼。其目的是為了能在iOS平臺上重用Android平臺、web伺服器端的Java代碼。伺服器端代碼的轉換由 GWT 完成。J2ObjC並不轉換UI代碼,這部分需要針對不同平臺分別開發。 我們在2012年發 ...
  • public class NetStateUtils { /** * 對網路連接狀態進行判斷 * * @return true, 可用; false, 不可用 */ public static boolean isNetworkConnected(Context context) { if (con ...
  • 相關的第三方類庫大家可以去github上下載 1.NSJSONSerialization 具體代碼如下 : 2.JSONKit 這是需要導入第三方類庫 3.SBJson 同樣需要導入第三方類庫 4.TouchJson 第三方類庫 ...
  • 文件處理: 常用操作: 增加: 刪除: 修改: 讀取: sd卡處理相關: 獲取: ...
  • 記憶體溢出就是軟體運行需要的記憶體,超出了java虛擬機給他分配的可用的最大記憶體 記憶體泄露就是在緩存圖片文字等等的時候,沒有關閉流所導致的記憶體泄露 ...
  • 當工作線程給主線程發送消息時,因為主線程是有looper的,所以不需要初始化looper,註意給誰發消息就關聯誰的handler,此時用的就是主線程的handler handler會把消息發送到MessageQueue隊列中,looper會不斷的去遍歷MessageQueue隊列,當一有消息時就會回 ...
  • 最終的演示如下 這次是用多線程進行圖片的下載與存儲,而且考慮到下載失敗,占點陣圖片的問題(第一張就是下載失敗的圖片) 閑話少說,上代碼吧,因為有一部分和上次的一樣,所以這裡只上傳不一樣的 依舊都是在ViewController.m中 1. 前兩個和前面的一致 operations使用來存儲下載圖片的線 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...