多线程
在今天的多线程中主要包括以下几个方面:①串行队列②并行队列③分组队列④一次性⑤障碍队列⑥延迟⑦重复
1. 串行队列
一个应用只有一个主线程, 主线程主要用于用户交互和界面显示
1 . 创建串行队列
//(1). 获取系统创建好的串行队列, 在主线程中实现线程同步(C 语言层级, 执行效率非常高, 但容易出现卡顿), 获取方法如下:
dispatch_queue_t queue1 = dispatch_get_main_queue();
//(2). 自己创建串行队列, 队列在子线程中实现线程同步
//第一个参数(const char *label)是队列的唯一标识
//第二个参数(dispatch_queue_attr_t attr)用于指定串行队列
dispatch_queue_t queue2 = dispatch_queue_create("com.baidu.www", DISPATCH_QUEUE_SERIAL);
2 . 往队列中添加任务
//第一个参数(dispatch_queue_t queue)是队列名
//第二个参数(<#^(void)block#>)是 block 块
dispatch_async(queue2, ^{//可以进行具体操作
NSLog(@"任务一 : %@", [NSThread currentThread]);//输出结果中的number 为 1时说明系统的队列
});
3 . 释放
//当使用 create 创建队列时,使用完之后需要释放
dispatch_release(queue2);
2. 并行队列
系统创建好了四个队列, 按照优先级分别是①DISPATCH_QUEUE_PRIORITY_BACKGROUND
②DISPATCH_QUEUE_PRIORITY_DEFAULT
③DISPATCH_QUEUE_PRIORITY_LOW
④DISPATCH_QUEUE_PRIORITY_HIGH
1 . 创建并发(并行)队列
//(1). 获取并使用系统创建好的并发队列
//第一个参数(long identifier)是队列的优先级
//第二个参数(unsigned long flags)是预留参数
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//(2). 自己创建并发队列
//第一个参数是唯一标识
//第二个参数是将该队列指定为并发队列
dispatch_queue_t queue2 = dispatch_queue_create("com.lanou3g.leo", DISPATCH_QUEUE_CONCURRENT);
2 . 往队列中添加任务
dispatch_async(queue2, ^{
NSLog(@"任务一 : %@", [NSThread currentThread]);
});
3 . 释放
dispatch_release(queue2);
3. 分组队列
当数据很大时, 可以使用分组队列,一部分一部分的请求数据
1 . 创建并行队列(这里以系统队列为例, 当然还可以使用自己创建的队列)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2 . 创建分组
dispatch_group_t group = dispatch_group_create();
3 . 往分组中添加任务
dispatch_group_async(group, queue, ^{
NSLog(@"请求 0 - 10M 的数据");
});
dispatch_group_async(group, queue, ^{
NSLog(@"请求10 - 20M 的数据");
});
dispatch_group_async(group, queue, ^{
NSLog(@"请求20 - 30M 的数据");
});
dispatch_group_async(group, queue, ^{
NSLog(@"请求30 - 40M 的数据");
});
//当分组内的所有任务完成之后触发
dispatch_group_notify(group, queue, ^{
NSLog(@"数据拼接操作");
});
4 . 释放
dispatch_release(group);
4. 一次
一次性线程, 顾名思义就是只执行一次的线程, 在 OC 中最突出的就是单例类的初始化
//单例类的初始化方法
+ (id)mainSingleton {
static Singleton *singleton = nil;
// 这是之前的定义方法
// @synchronized(self) {
// if (!singleton) {
// singleton = [[Singleton alloc] init];
// }
// }
// return singleton;
//GCD : 创建的队列都是轻量级的, 这里用到的都是 GCD
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//写只执行一次的代码
singleton = [[Singleton alloc] init];
});
return singleton;
}
5. 障碍队列
障碍任务的作用: 可以保证障碍之后到的并发任务, 必须在张安之前的并发任务全部执行完成之后, 才可以继续往下执行(注意: 如果添加障碍任务, 必须要使用自己创建的并发队列)
1 . 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("com.baidu.www", DISPATCH_QUEUE_CONCURRENT);
2 . 往队列中添加队列
dispatch_async(queue, ^{
NSLog(@"A 写入文件file1");
});
dispatch_async(queue, ^{
NSLog(@"B 写入文件file2");
});
dispatch_async(queue, ^{
NSLog(@"C 写入文件file3");
});
//添加障碍任务
dispatch_barrier_async(queue, ^{
NSLog(@"这是一个障碍任务");
});
dispatch_async(queue, ^{
NSLog(@"D 读取文件file3");
});
dispatch_async(queue, ^{
NSLog(@"E 读取文件file1");
});
3 . 释放
dispatch_release(queue);
6. 延迟
//第一个参数(delayInSeconds) 是延迟时间(秒)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"hh");
});
//其中的dispatch_get_main_queue() 是在主线程中执行, 如果想在子线程中执行, 此处改为子线程即可
7. 重复
//dispatch_get_main_queue 主线程重复时即使重复一次, 也会卡死
//反复执行并发队列至少有一次在主线程中执行.
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
NSLog(@"反复执行的次数%ld, 当前线程%@", index, [NSThread currentThread]);
});//size_t 之后要添加参数名, 比如 index
注意
1 . 关于dispatch_queue_create
a. 在使用dispatch_queue_create方法创建自己的队列时, 需要注意第二个参数用于指定串行队列或是并行队列, 具体如下:
①DISPATCH_QUEUE_CONCURRENT : 并行队列
②DISPATCH_QUEUE_SERIAL : 串行队列
b. 在使用dispatch_queue_create方法创建自己的队列之后, 需要将该队列释放(只要方法中有 create 的都需要释放)
2 . 关于dispatch_async
使用异步方法而不是同步方法是因为, 同步方法易出现卡顿现象, 用户交互差