前言 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