关于IOS多线程
1.线程的概念
1个cpu执行的cpu命令列为一条无分叉路径,即为线程
如果这种无分叉路径有多条,这就是多线程
在学习操作系统的时候学过,cpu的抢占机制–时间片轮转
所以多线程程序的某个线程可以和其它多个线程反复进行上下文切换,这就看上去像1个cpu核能够并列执行多个线程一样
2.多线程导致的一些问题
- 数据竞争问题:比如一个线程修改数据而其它一个线程这个相同时刻访问这个数据,这就导致数据竞争
- 死锁问题:导致死锁原因, 互斥条件:一个资源每次只能被一个进程使用。请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
- 太多线程比较消耗内存:例如:cpu寄存器在时间片轮转时候,等待唤醒的线程会将cpu的寄存器的信息保存到各自专用的内存块中,一旦唤醒,立刻复原cpu寄存器等信息。
多线程的优点也是大于缺点的,在执行长时间的处理时仍能保证用户界面的响应性能
3.GCD中的同步(synchronize)和异步(asynchronize)
//不会阻塞主线程,异步的,可以先执行后面代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
//会阻塞主线程等待block中执行完毕
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
4.GCD的并行(concurrent)和串行(serial)
- 串行队列:会等待现在处理结束,也就是队列中的任务顺序执行,等待前一个任务结束,才开始下一个任务
- 并行队列:不等待现在执行处理结束,就是队列中所有任务都立刻开始执行,没有先后顺序
//串行队列
dispatch_queue_t serial_queue = dispatch_queue_create("seral", DISPATCH_QUEUE_SERIAL);
//主队列 属于串行的队列 serial,由于主线程只有一个,所以它是串行的,可以思考一下
dispatch_queue_t main_queue = dispatch_get_main_queue();
//异步 全局(并行)
dispatch_async(global_queue_height, ^{
//并行任务
dispatch_async(main_queue, ^{
//主队列任务
});
});
//主线程同步会出现死锁,阻塞主线程,所以只能使用主线程异步
dispatch_async(main_queue, ^{
//主队列任务
});
并行队列
//全局队列 属于并行队列 concurrent
dispatch_queue_t global_queue_height = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
//并行队列
dispatch_queue_t concurrnt_queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
```c
全局队列和主队列是IOS自定的两个队列
dispatch_queue_t global_queue_height = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
全局队列的优先级 DISPATCH_QUEUE_PRIORITY_HIGH,DISPATCH_QUEUE_PRIORITY_LOW,DISPATCH_QUEUE_PRIORITY_DEFAULT,DISPATCH_QUEUE_PRIORITY_BACKGROUND有四种种优先级
## 5.dispatch_set_target_queue 变更两个队列的优先级方法 ##
## 6.dispatch_after ##
并不是在指定时间后执行处理,而是到指定时间追加处理到队列(queue)中去执行
在下面例子中由于在主队列(main queue)的Runloop中执行。
第二个参数也可以指定具体某时某刻
```c
dispatch_time_t outtime = dispatch_time(DISPATCH_TIME_NOW, 15ull*NSEC_PER_SEC);
dispatch_after(outtime, dispatch_get_main_queue(), ^{
//15ull后添加到队列中
});
7.关于DISPATCH_GROUP
追加到队列中的任务如果想在结束之后进行处理,可以将其放入group中
- 队列执行完之后会调用dispatch_group_notify函数
- 也可以使用dispatch_group_wait设置超时
- 也可以使用dispatch_barrier_async设置执行到某个位置中断,等待前面执行完,再执行后面的队列
- dispatch_apply该函数按照指定次数将指定的block追加到指定的队列(queue)中并等待全部处理结束 例子中NSLog(@"%zu",index);将添加到global_queue1中执行10次,等待结束后执行后面代码
- dispatch_suspend/dispatch_resume在追加大量的任务,有时候希望不执行这个任务就让其挂起/…恢复
- dispatch_once这个在单例模式中可以使用,当然也可以代替懒汉加载模式,保证程序在应用执行中只执行一次
- dispatch_I/O读取/写入 较大文件并列读取(写入),提高读(写)取速度
- dispatch semaphore解决数据不同步的一些问题的,进行排它控制
dispatch_group_t group_t = dispatch_group_create();
dispatch_group_async(group_t, queue_global12, ^{
});
dispatch_group_async(group_t, queue_global12, ^{
});
//队列执行完成后调用
dispatch_group_notify(group_t, queue_global12, ^{
});
dispatch_group_wait(group_t, DISPATCH_TIME_FOREVER);
dispatch_time_t mytime = dispatch_time(DISPATCH_TIME_NOW, 1ull*NSEC_PER_SEC);
long result = dispatch_group_wait(group_t, mytime);
if (result==0) {
//group中的全部处理结束
}else{
//group的某一个处理还在进行中
}
dispatch_barrier_sync(global_queue1, ^{
//等到追加到concurrent dispatch queue 执行完毕之后才将制定的处理追加到指定的queue
});
dispatch_apply(10, global_queue1, ^(size_t index) {
NSLog(@"%zu",index);
});
//挂起
dispatch_suspend(global_queue1);
// 恢复
dispatch_resume(global_queue1);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程1
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程2
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
// 两个线程都执行完
});
最后关于一个缓存类,缓存有个特点数据频繁读取,写入次数有限,如果使用互斥步锁(NSLock,@synichronized,dispatch_semaphore_t等)资源消耗比较多,可以了解读写锁相关的内容
使用dispatch_queue_create创建的队列在并行多任务情况下,dispatch_barrier_async函数提交的任务会等它前面的任务执行完才开始,然后它后面的任务必须等它执行完毕才能开始.
@interface ICatche : NSObject
+(instancetype)sharedCatch;
- (id)cacheWithKey:(id)key;
-(void)setCatcheObject:(id)obj withKey:(id)key;
@end
#import "ICatche.h"
@interface ICatche()
{
dispatch_queue_t queue;
}
@property(nonatomic,strong)NSMutableDictionary *tempDic;
@end
@implementation ICatche
static ICatche *instance;
+(instancetype)sharedCatch{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc]init];
});
return instance;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
-(instancetype)init{
if (self=[super init]) {
queue = dispatch_queue_create("Icatch_queue", DISPATCH_QUEUE_CONCURRENT);
self.tempDic = [NSMutableDictionary dictionaryWithCapacity:20];
}
return self;
}
//读取数据
- (id)cacheWithKey:(id)key{
__block id obj;
dispatch_sync(queue, ^{
obj = [self.tempDic objectForKey:key];
});
return obj;
}
//写入数据
-(void)setCatcheObject:(id)obj withKey:(id)key{
dispatch_barrier_async(queue, ^{
[self.tempDic setObject:obj forKey:key];
});
}
@end
[NSThread的用法](https://www.jianshu.com/p/686dbf4bbb52)