串行队列:
1、自己创建
2、主队列,特殊的串行队列(和主线程相关联),放在主队列中的任务,都会放到主线程中执行
主队列+异步函数
主队列优先,不会开启线程,所有的任务都在主线程中串行执行
串行队列+异步函数
不会开启子线程,所有的任务在当前线程中串行执行
并发队列+同步函数
不会开启子线程,所有的任务在当前线程中串行执行
并发队列+异步函数
会开启多条子线程,所有的任务并发执行
例如:
同步函数+主队列。会造成死锁
原因:主队列中有任务的时候,主队列就会安排主线程来执行该任务。但是在调度之前会检查主线程的状态,住过主线程在忙,就暂停调度。 知道主线程空闲为止。
dispatc_queue_t queue = dispathch_get_main_queue();//任务需要由主线程来执行,但是现在主线程在 执行第一个sync函数
NSlog(@"0");
dispatch_sync(queue,^{
NSlog(@"1")';
});
dispatch_sync(queue,^{
NSlog(@"2")';
});
dispatch_sync(queue,^{
NSlog(@"3")';
});
dispatch_sync(queue,^{
NSlog(@"4")';
});
dispatch_sync(queue,^{
NSlog(@"5")';
});
注意:
如果以上整段代码放在子线程中执行,则不会造成死锁
异步函数+主队列,不会造成死锁
dispatc_queue_t queue = dispathch_get_main_queue();//任务需要由主线程来执行,但是现在主线程在 执行第一个sync函数
NSlog(@"0");
dispatch_async(queue,^{
NSlog(@"1")';
});
dispatch_async(queue,^{
NSlog(@"2")';
});
dispatch_async(queue,^{
NSlog(@"3")';
});
dispatch_async(queue,^{
NSlog(@"4")';
});
dispatch_async(queue,^{
NSlog(@"5")';
});
原因:执行到1的时候,需要让主队列执行任务,但是主队列现在不空闲,又因为是异步函数,就会跳过1往下执行,而不会一直等待,同理跳过2、3、4、5,直到5个任务都添加到队列中,后面没有任务了,既然没有任务了,那就说明主线程终于空闲了。 现在就可以来执行这几个任务了。是把下边的任务全部过掉后,在回过头来之星这几个任务,然后依次取出任务执行,
perfomerSelecotr相关
- (void)viewDidLoad{
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
[thread start];
}
- (void)threadMethod{
[self performSelector:@selector(delayTest) withObject:nil afterDelay:0.1];
}
- (void)delayTest{
NSlog(@"This delayTest method");
}
如果在子线程中使用延时方法,delayTest是不会被执行的
原因:在子线程里调用延时函数,需要计时器,而子线程默认不自动创建runloop,导致没有计时器工作
解决方案:
1、在子线程里启动runloop
- (void)threadMethod{
[self performSelector:@selector(delayTest) withObject:nil afterDelay:0.1];
//启动runloop
[[NSrunloop currentRunloop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[[NSrunloop currentRunloop] run ];
}
2、调用GCD的延时函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runTime2];
});
PerformSelector:afterDelay 相关
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;
区别在于第二个方法里指定了Runloop的mode,
#######注意:方法是异步的,只能在主线中执行
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"before performdeleay");
[self performSelector:@selector(deleayTest:) withObject:@"delaytest" afterDelay:0];
sleep(6);
NSLog(@"after performdeleay");
}
- (void)deleayTest:(NSString *)test {
NSLog(@"doSomething:%@, currentThread = %@", test , [NSThread currentThread]);
}
打印结果是:
before performdeleay
(6s 后)
after performdeleay
doSomething:delaytest, currentThread = <NSThread: 0x7fdf73706c70>{number = 1, name = main}
可以看到,这个方法不会阻塞当前线程,而是把selector加入到主队列里,delay之后执行方法。即使delay时间为0,如果主线程在执行任务,那只能等到主线程执行完所有任务以后才会去执行selector。
那么delay的即时时间是从什么时候开始的呢,performSelector时候开始计算,就算主线程在阻塞也会计算时间,当主线程执行完以后,如果到了delay的时间,就会去执行selector,如果不到就继续deleay。
网友评论