多线程核心概念: 一个任务 / 两种队列 / 两种函数.
1. 一个任务: 执行什么操作;
2. 执行任务的两种队列:
(1)并发队列(Concurrent Dispatch Queue): 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务),
前提是在dispatch_async异步函数下执行;
(2)串行队列(Serial Dispatch Queue):一个任务执行完毕后,再执行下一个任务.
2.1 并发队列和串行队列的区别: 任务的执行方式不同
---------------------------------------------------
3. 执行任务的两种函数:
(1)同步函数dispatch_sync < synchronous>: 不具备开启新线程的能力;
(2)异步函数dispatch_async : 具备开启新线程的能力
3.1 同步和异步区别:能不能开启新的线程
多线程创建队列的两种方式
1. 通过dispatch_queue_create函数创建一个队列;
2. 直接获取现成的主线程dispatch队列或者全局的dispatch队列。
GCD实现的Timer如图所示:
核心代码:
//开始
- (IBAction)startTimer:(id)sender {
__block int startTimer = 0;
__weak typeof(self) weakself = self;
//开启专门的线程处理timer
self.timerQueue = dispatch_queue_create("TimerQueue", 0);
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _timerQueue);
/*----打出dispatch_s直接就出现下边的代码块了---------*/
/**
* 第一个参数: dispatch_source_t, Dispatch Source
* 第二个参数: 开始时刻;
* 第三个参数: 间隔<例子中是一秒>;
* 第四个参数: 精度<最高精度将之设置为0>
*/
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//函数回调
dispatch_source_set_event_handler(self.timer, ^{
//回主线刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
weakself.label.text = [NSString stringWithFormat:@"%d", startTimer++];
});
});
//默认的dispatch_source_t是暂停, 开始监听
dispatch_resume(self.timer);
/*----打出dispatch_s直接就出现上边的代码块了---------*/
}
dispatch_queue_create创建两种队列
//创建一个串行dispatch队列, 第二个参数将其设置成NULL。
dispatch_queue_t mySerialDispatchQueue =
dispatch_queue_create("com.example.gcd", NULL);
//创建一个串行dispatch队列, 第二个参数就设置成DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t myConcurrentDispatchQueue =
dispatch_queue_create( "com.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
具体操作
1.直接获取线程的队列
1. 主线程dispatch队列: 所有任务都在主线程上执行, 它是一个串行队列。
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
--------------------------------------------------
2. 全局的dispatch队列: 它是并行队列,可以在应用程序的任何地方使用它们。
一般可以直接使用该队列. 有四种优先级:high, default, low 和 background。
dispatch_queue_t globalDispatchQueueDefault =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2. dispatch_set_target_queue 设置优先级
dispatch_set_target_queue函数用于设置一个”目标”队列。创建队列后,你可以用这个函数来修改队列的优先级。
3. dispatch_group_async 分组
等dispatch队列中的所有任务完成了才执行另外一个任务。
dispatch_group_async就可以上场了.
4. dispatch_barrier_async 栅栏方式
dispatch_barrier_async函数用于等待队列中其他任务完成。
1. 当你访问数据库或者一个文件的时候,你可以用串行队列来避免数据冲突。
2. 多个读取操作是可以同时进行的,这样可以更高效的访问数据,但更新数据时必须等其他操作结束, 如果使用前两种方式会很麻烦.
3. dispatch_barrier_async 创建了一个并发队列,然后向队列中添加了一些读取操作。会等本次操作以前的完全执行才执行.
5. dispatch_apply
dispatch_apply函数会像dispatch_sync函数一样等待所有任务完成,
//串行队列是有序的
dispatch_apply(5, syncQueue, ^(size_t index) {
NSLog(@"++++++ %zu", index);
});
顺序: 01234
//并发队列是无序
dispatch_apply(5, asyncQueue, ^(size_t index) {
NSLog(@"----%zu", index);
});
顺序不固定
6. dispatch_semaphore_t 信号量
并发读取或更新数据时
很容易造成数据冲突或者程序崩溃。
当你需要对一小部分间隔时间较短
的任务做并发控制
的时候,Semaphore(信号量)会比串行队列或者dispatch_barrier_async更好用。
Dispatch semaphore是一个带有一个计数器的信号量。信号量有点像一个交通信号标志,标志起来的时候你
可以走,标准落下的时候你要停下来。Dispatch semaphore用计数器来模拟这种标志。计数器为0,队列暂停
执行新任务并等待信号;当计数器超过0后,队列继续执行新任务,并减少计数器。
//用dispatch_semaphore_create函数。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//dispatch_semaphore_wait函数用于等待一个信号量。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
long result = dispatch_semaphore_wait(semaphore, time);
if (result == 0){
/*
* 信号量计数器大于等于1。
* 或者在指定的等待时间超时前,信号量计数器变成了大于等于1的数字。
* 计数器会自动减一
*
* 在这里,可以安全地运行你的任务了。
*/
}else{
/*
* 因为信号量计数器是0,就只能等待超时了。
*
* 这里处理等待超时的情况。
*/
}
GCD支持方法示例代码
GCD实现的Timer代码
GCD使用详解
更多精彩内容请关注“IT实战联盟”哦~~~