为了简化多线程应用的开发,iOS提供了GCD来实现多线程。
GCD的两个核心概念是队列和任务。
- 队列:队列负责管理开发者提交的任务,GCD队列始终以先进先出的方式来处理任务,但由于任务的执行时间不相同,因此先处理的任务并不一定先结束,队列既可以是串行队列,也可以是并发队列,串行队列每次只处理一个任务,必须前一个任务执行完成后,才能执行下一个任务;并发队列则可同时处理多个任务,因此将会有多个任务并发执行。
对列底层会维护一个线程池来处理用户提交的任务,线程池的作用就是执行队列管理的任务。串行队列底层的线程池只要维护一个线程即可,并发队列的底层则需要维护多个线程
- 任务:任务就是用户提交给队列的工作单元,这些任务将会提交给队列底层维护的线程池执行,因此这些任务会以多线程的方式执行。
dispath_group_notify : 分发--组--通知
DISPATCH_QUEUE_ SERIAL: 发送--行列--连续的
CONCURRENT:同时发生的
对于打算使用GCD实现多线程的开发者来说,使用GCD只要遵守两个步骤即可。
- 创建队列
GCD队列可分为两种:串行队列 和 并行队列
√:创建串行队列 dispatch_queue_t queue3 = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
√:.创建并发队列 dispatch_queue_t queue4 = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
2.将任务提交给队列
√:dispatch_async(dispatch_queue_t queue, ^(void)block);
√:dispatch_sync(dispatch_queue_t queue, ^(void)block);
在代码块中直接调用更新UI界面的方法:
-(void)loadImage:(int)index{
dispatch_queue_t mainQueue=dispatch_get_main_queue();获取主线程
回归主线程
dispatch_sync(mainQueue, ^{
UIImageView* imageView=_arrImage[index];
imageView.image=[UIImage imageWithData:data];
});
}
-----------加锁--------
√:加锁时属性使用atomic
nonatomic 与atomic区别:
//nonatomic 属性读取的是内存数据,(寄存器计算好的结果)
//atomic保证直接读取寄存的数据,(这样就不会出现一个线程在修改数据,而另一个线程都去了修改之前的数据)***永远保证同时只有一个线程在访问一个属性
_lock=[[NSLock alloc]init];
[_lock lock];//上锁
[_lock unlock];//解锁
加锁方法1:使用时,把资源抢夺部分的代码放到lock和unlock之间 锁需要初始化
[_lock lock];//上锁
//子线程
if (_tickets.count>0) {
NSLog(@"%d号顾客买到的票号:%@",i,[_tickets lastObject]);
[_tickets removeLastObject];
}else{
NSLog(@"%d号顾客晚了一步",i);
}
[_lock unlock];//解锁
方法2:@synchronized(self) {}
//当一个线程A进入加锁代码后,另一个线程B就无法访问他了。只有当线程A执行完加锁的任务后,B线程才能访问枷锁代码
for (int i= 0; i<BUYER; i++) {
dispatch_async(queue, ^{
@synchronized(self) {
if (_tickets.count>0) {
NSLog(@"%d号顾客买到的票号:%@",i,[_tickets lastObject]);
[_tickets removeLastObject];
}else{
NSLog(@"%d号顾客晚了一步",i);
}
}