//1.創建串行或變行隊列
//創建串行或變行隊列
- (void)createDispatchQueue
{
//法1 dispatch_queue_create (NULL,默認是串行)
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.tzyj.myConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{NSLog(@"block on myConcurrentDispatchQueue");});//block會持有改隊列,所以下面釋放隊列沒有任何影響
dispatch_release(myConcurrentDispatchQueue);//ARC也要, 因為ARC下也沒有DispatchQueue管理
{//法1補充 隊列優先級修改
//dispatch_queue_create創建的隊列默認是DISPATCH_QUEUE_PRIORITY_DEFAULT,如何修改優先級 如DISPATCH_QUEUE_PRIORITY_BACKGROUND
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.tzyj.mySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
}
//法2 用系統標準獲取Dispatch Queue, 不用自己release
//主線程隊列 串行隊列
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
//global隊列 并行隊列
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t gl0balDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t gl0balDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
//常用gcd框架
//global dispatch queue 中執行block
dispatch_async(globalDispatchQueueDefault, ^{
//可并行處理的操作
//main dispatch queue中執行block
dispatch_async(mainDispatchQueue, ^{
//只能在主線程執行的處理
});
});
}
//2.延遲執行和特定時間執行
//2.延遲執行和特定時間執行
dispatch_time_t getDispatchTimeByDate(NSDate *date); //C語言函數原型申明
- (void)testGCDTime
{
//相對時間 3s后開始追加任務到block dispatch_after 指定時間后追加處理到dispatch queue中,并不是馬上執行處理。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"waited at least 3 seconds");
});
//絕對時間 20221009 11:11:11
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
NSDate *date=[dateFormatter dateFromString:@"20221009111111"];
dispatch_time_t absolutTime = getDispatchTimeByDate(date);
dispatch_after(absolutTime, dispatch_get_main_queue(), ^{
NSLog(@"absolute time");
});
}
//c語言 獲取絕對時間 dispatch_walltime
dispatch_time_t getDispatchTimeByDate(NSDate *date)
{
NSTimeInterval interval;
double second,subsecond;
struct timespec time;
dispatch_time_t milestone;
interval = [date timeIntervalSince1970];
subsecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subsecond * NSEC_PER_SEC;
milestone = dispatch_walltime(&time, 0);
return milestone;
}
3.//多個任務都結束后再執行其它任務,用dispatch_group_
- (void)testDispatchGroup
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"blk0");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blk2");
});
if(1)//法1
{
dispatch_group_notify(group, queue, ^{
NSLog(@"all done");
});
}
else if(2)//法2
{
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//永遠等待,最好不要子啊主線程上這種用,會有卡死情況出現
}
else if(21)//法2 用法2 超時機制<eg超時3s>
{
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
long result = dispatch_group_wait(group, time);
if (result == 0) {
NSLog(@"all done");
} else {
NSLog(@"還有沒有執行完成的");
}
}
dispatch_release(group); //如果是在OS X 10.8或iOS 6以及之后版本中使用,Dispatch Group將會由ARC自動管理,如果是在此之前的版本,需要自己手動釋放。
}
4.//數據庫讀寫,避免數據競爭問題思想, dispatch_barrier_sync
//思想 讀操作可以并行處理,追加到并行隊列(concurrent dispatch queue); //沒有任何讀的操作下,將寫處理追加到串行隊列,寫沒處理完之前 不可以讀
//法2 dispatch_barrier_sync(//法1 用dispatch group和dispatch_set_target_queue實現)
- (void)testDispatchBarrierAsync
{
//并行隊列 讀操作可以并行處理
dispatch_queue_t queue = dispatch_queue_create("com.tzyj.forBarrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{NSLog(@"blk0_for_reading");}); //讀
dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});
//dispatch_barrier_sync函數會等待追加到并行隊列queue的任務全部處理結束后,在將指定的任務(blk_for_writing)追加到并行隊列queue中,等任務(blk_for_writing)結束后,并行隊列queue恢復為一般的動作。
dispatch_barrier_sync(queue, ^{
NSLog(@"blk_for_writing"); //寫
});
dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk5_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk6_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk7_for_reading");});
}
5.注意以下死鎖情況
Paste_Image.png
6.重復追加block 到隊列中
//法2 dispatch_barrier_sync(//法1 用dispatch group和dispatch_set_target_queue實現)
- (void)testDispatchBarrierAsync
{
//并行隊列 讀操作可以并行處理
dispatch_queue_t queue = dispatch_queue_create("com.tzyj.forBarrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{NSLog(@"blk0_for_reading");}); //讀
dispatch_async(queue, ^{NSLog(@"blk1_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk2_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk3_for_reading");});
//dispatch_barrier_sync函數會等待追加到并行隊列queue的任務全部處理結束后,在將指定的任務(blk_for_writing)追加到并行隊列queue中,等任務(blk_for_writing)結束后,并行隊列queue恢復為一般的動作。
dispatch_barrier_sync(queue, ^{
NSLog(@"blk_for_writing"); //寫
});
dispatch_async(queue, ^{NSLog(@"blk4_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk5_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk6_for_reading");});
dispatch_async(queue, ^{NSLog(@"blk7_for_reading");});
}
7.//更新數據時候,如果并行處理會導致數據不一致,有時程序還會異常結束,
//解決:通過信號機制dispatch_semaphore_ 可以保證更新數據的時候只有一個線程在執行
-(void)testDispatchSemaphore
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//保證只有一個線程
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)); //最多等待3s;
long result = dispatch_semaphore_wait(semaphore, time);
if (result == 0) {
//在規定的待機時間內 dispatch semaphore信號計數值大于等于1,所有信號計數減1
//可以執行排他的控制處理
}else{
//由于信號值為0,所以在指定時間內一直待機
}
dispatch_release(semaphore);
//常用場景:更新數組數據
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//生成dispatch semaphore,初始值為1,保證可訪問數組對象的線程同時只能有1個
semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i=0; i<10000; i++)
{
dispatch_async(queue, ^{
//一直等待dispatch semaphore信號計數值大于等于1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//由于初始為1,信號值減1,dispatch_semaphore_wait函數返回
//此時信號計算值為0, 其他線程都只能等待, 只有一個線程訪問,所以可以安全更新數據
[array addObject:[NSNumber numberWithInt:i]];
//排他控制結束后, 需要其他線程(通過dispatch_semaphore_wait函數)也執行,需要將信號值加1
dispatch_semaphore_signal(semaphore);
});
}
dispatch_release(semaphore);
}
8.dispatch_once 保證函數在應用程序里只執行一直
多線程環境下和安全
-(void)testDispatchOnce
{
//老方法 在多線程環境可能會執行多次
static int initialized = NO;
if (initialized == NO) {
//初始化動作
initialized = YES;
}
//以后盡量用下面的方法替換上面的邏輯
//用dispatch_once 多線程下也安全
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//初始化
});
}
//單例模式 推薦用上面第一種
+ (HsOptionTQuoteDataModel *)sharedManager
{
static HsOptionTQuoteDataModel *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
static HsConfigration *sharedSingletonManager = nil;
+ (HsConfigration *)sharedManager
{
@synchronized(self) {
if (sharedSingletonManager == nil) {
sharedSingletonManager = [[self alloc] init]; // assignment not done here
}
}
return sharedSingletonManager;
}
9.含block的自定義網絡回調接口
Paste_Image.png
如果你發現本文對你有所幫助,如果你認為其他人也可能受益,請把它分享出去。