在 iOS 开发中,多线程是提升应用性能、优化用户体验的关键技术。而 GCD(Grand Central Dispatch) 是 Apple 提供的一套强大、高效的并发编程接口,它基于 C 语言实现,封装了底层线程管理的复杂性,让开发者可以专注于任务本身。
本文将系统讲解 GCD 的核心概念、使用方式、常见组合场景以及高级用法,并辅以代码示例,助你彻底掌握 GCD。
一、什么是 GCD?
GCD(Grand Central Dispatch) 是 Apple 在 Mac OS X 10.6(Snow Leopard)和 iOS 4 中引入的多核并发编程框架。其主要特点包括:
自动利用多核 CPU 资源;
基于“队列”模型管理任务;
自动管理线程生命周期(创建、调度、销毁);
使用 Block(闭包)作为任务单元,语法简洁;
底层由系统维护线程池,高效且安全。
✅ 一句话总结:GCD 让你只需关心“做什么”,而不用操心“怎么做线程”。
二、GCD 的两个核心概念
1. 任务(Task)
任务是你希望在线程中执行的一段代码,通常以 Block 形式传递:
^{
// 执行代码
}
任务有两种提交方式:
⚠️ 注意:
dispatch_async不一定开启新线程!例如向主队列异步提交任务,仍会在主线程执行。
2. 队列(Dispatch Queue)
队列是任务的容器,遵循 FIFO(先进先出) 原则。GCD 提供两类队列:
(1)串行队列(Serial Queue)
每次只执行一个任务;
任务按顺序依次执行;
默认只使用一个线程(除非是主队列)。
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
(2)并发队列(Concurrent Queue)
可同时执行多个任务;
系统根据资源自动分配多个线程;
仅在异步提交时才并发执行。
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
特殊队列:
主队列(Main Queue):
dispatch_queue_t mainQueue = dispatch_get_main_queue();串行队列;
所有任务在 主线程 执行;
UI 更新必须在此队列进行。
全局并发队列(Global Queue):
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);系统提供的并发队列;
支持不同优先级(如
HIGH,DEFAULT,LOW,BACKGROUND)。
三、GCD 的六种基本组合
🔥 重点警告:
dispatch_sync(dispatch_get_main_queue(), ^{...})在主线程中调用会导致 死锁!
因为 sync 会等待任务完成,而主队列任务需等当前 runloop 结束才能执行,形成循环等待。
四、代码示例
1. 异步并发执行(常用后台任务)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 耗时操作:网络请求、文件读写等
NSLog(@"后台线程:%@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程更新 UI
self.label.text = @"加载完成";
});
});
2. 串行队列保证顺序执行
dispatch_queue_t serial = dispatch_queue_create("com.example.download", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 5; i++) {
dispatch_async(serial, ^{
NSLog(@"任务 %d - %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
});
}
// 输出:0,1,2,3,4 依次打印,间隔1秒
3. 避免主队列同步死锁
❌ 错误写法(在主线程中):
dispatch_sync(dispatch_get_main_queue(), ^{ /* ... */ }); // 卡死!
✅ 正确做法:
dispatch_async(dispatch_get_main_queue(), ^{ /* UI 更新 */ });
五、GCD 高级用法
1. dispatch_once:线程安全的单例初始化
+ (instancetype)sharedInstance {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
2. dispatch_after:延时执行
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^{
NSLog(@"2秒后执行");
});
3. dispatch_group:任务组等待
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{ /* 任务1 */ });
dispatch_group_async(group, queue, ^{ /* 任务2 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"所有任务完成!");
});
4. dispatch_barrier_async:读写锁(用于自定义并发队列)
// 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("com.example.barrier", DISPATCH_QUEUE_CONCURRENT);
// 读操作(并发)
dispatch_async(queue, ^{ /* 读取数据 */ });
// 写操作(屏障,等待所有读完成后再执行,执行时阻塞其他任务)
dispatch_barrier_async(queue, ^{
// 安全写入
});
5. dispatch_semaphore:信号量控制并发数
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3); // 最多3个并发
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 模拟耗时任务
NSLog(@"执行任务 %d", i);
sleep(2);
dispatch_semaphore_signal(semaphore);
});
}
六、最佳实践建议
UI 操作永远在主队列;
避免在主线程做耗时操作(防止卡顿);
慎用
dispatch_sync,尤其不要同步提交到当前队列;优先使用全局队列,除非需要严格顺序(用串行队列);
善用
dispatch_group和dispatch_semaphore控制复杂并发逻辑。
七、结语
GCD 是 iOS 并发编程的基石。掌握它不仅能写出高性能代码,还能避免常见的线程安全问题。希望本文能帮你建立起对 GCD 的系统认知。