多线程的运用
2018-12-29 本文已影响12人
guoguojianshu
同步串行队列
- (IBAction)sender1:(UIButton *)sender {
// 同步串行 第一个参数为queue的名字,第二个参数为是串行队列还是并行队列,NULL或者为DISPATCH_QUEUE_SERIAL为串行,DISPATCH_QUEUE_CONCURRENT为并行队列
//同步串行队列会阻塞主线程,一个任务结束了,下一个任务才会开始,按顺序进行
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
for (int n = 0; n<3; n++) {
dispatch_sync(queue, ^{
for (int i = 0; i<50000; i++) {
if (i == 0) {
NSLog(@"线程开始 %d %@",n,[NSThread currentThread]);
}
if (49999== i) {
NSLog(@"线程结束 %d %@",n,[NSThread currentThread]);
}
}
});
}
NSLog(@"线程有没有阻塞%@",[NSThread currentThread]);
}
屏幕快照 2018-12-29 下午2.00.35.png
同步并发队列
- (IBAction)sender2:(UIButton *)sender {
// 第一个参数为queue的名字,第二个参数为是串行队列还是并行队列,NULL或者为DISPATCH_QUEUE_SERIAL为串行,DISPATCH_QUEUE_CONCURRENT为并行队列
// 同步并发 会阻塞主线程,一个任务结束了,下一个任务才会开始,按顺序进行,并行队列同步执行会阻塞当前线程。且都是按顺序执行,前一个完成,后一个才开始。(注意:此处的按顺序一个一个执行和串行队列不同,此处是因为同步操作会阻塞当前线程,从打印结果看这三个操作都在主线程,当第一个操作完成,线程才解除阻塞,然后执行下一个,于是一个一个执行)从打印结果看,全在主线程执行的,所以同步任务不会开辟线程。
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
for (int n= 0; n<3; n++) {
dispatch_sync(queue, ^{
for (int i = 0; i<50000; i++) {
if (0 == i) {
NSLog(@"线程开始 %d %@",n,[NSThread currentThread]);
}
if (49999== i) {
NSLog(@"线程结束 %d %@",n,[NSThread currentThread]);
}
}
});
}
NSLog(@"线程有没有阻塞%@",[NSThread currentThread]);
}
屏幕快照 2018-12-29 下午2.00.35.png
异步串行队列
- (IBAction)send3:(UIButton *)sender {
// 异步串行 异步操作不会阻塞主线程,队列决定开几个线程,然后交给异步进行调度操作,串行队列是一个结束之后,下一个才会开始
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
for (int n= 0; n<3; n++) {
dispatch_async(queue, ^{
for (int i = 0; i<50000; i++) {
if (0 == i) {
NSLog(@"线程开始 %d %@",n,[NSThread currentThread]);
}
if (49999== i) {
NSLog(@"线程结束 %d %@",n,[NSThread currentThread]);
}
}
});
}
NSLog(@"线程有没有阻塞%@",[NSThread currentThread]);
}
屏幕快照 2018-12-29 下午5.16.14.png
异步并发队列
- (IBAction)send4:(UIButton *)sender {
// 异步并发 并发队列可以开启多个线程,可以同时执行,执行的时间可以看出来是同时执行的,并发的
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
for (int n = 0; n<3; n++) {
dispatch_async(queue, ^{
for (int i = 0; i<50000; i++) {
if (0 == i) {
NSLog(@"线程开始 %d %@",n,[NSThread currentThread]);
}
if (49999== i) {
NSLog(@"线程结束 %d %@",n,[NSThread currentThread]);
}
}
});
}
NSLog(@"线程有没有阻塞%@",[NSThread currentThread]);
}
屏幕快照 2018-12-29 下午5.38.11.png
队列组
- (IBAction)sender5:(UIButton *)sender {
// 队列组
// 创建一个组
dispatch_group_t group = dispatch_group_create();
// 创建一个自定义的并发队列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
// 第一参数是优先级 第二个参数是保留字段永远都是0
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_async(group, globalQueue, ^{
for (int i = 0; i<3; i++) {
NSLog(@"全局并发队列%d %@",i,[NSThread currentThread]);
}
});
dispatch_group_async(group, queue, ^{
for (int i = 0; i<3; i++) {
NSLog(@"自定义并发队列%d %@",i,[NSThread currentThread]);
}
});
dispatch_group_async(group, mainQueue, ^{
for (int i = 0; i<3; i++) {
NSLog(@"主队列%d %@",i,[NSThread currentThread]);
}
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成%@",[NSThread currentThread]);
});
NSLog(@"线程有没有阻塞%@",[NSThread currentThread]);
// 总结:队列组的线程只能管理大概的顺序,也就是队列组的前面和后面的顺序的,前面的顺序执行时候不可能存在严格的顺序,只用这个队列组全部执行完毕后,才能通知队列组的工程是有顺序的
}
屏幕快照 2019-01-01 下午4.02.09.png
栅栏
- (IBAction)sender6:(id)sender {
// 栅栏
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
for (int n = 0; n < 3; n++) {
dispatch_async(myQueue, ^{
for (int i = 0; i<50000; i++) {
if (0 == i) {
NSLog(@"前面的任务%d开始 %@",n,[NSThread currentThread]);
}
if (49999 == i) {
NSLog(@"前面的任务%d完成 %@",n,[NSThread currentThread]);
}
}
});
}
dispatch_barrier_async(myQueue, ^{
NSLog(@"执行barrier");
});
for (int n = 0; n < 3; n++) {
dispatch_async(myQueue, ^{
for (int i = 0; i<50000; i++) {
if (0 == i) {
NSLog(@"后面的任务%d开始 %@",n,[NSThread currentThread]);
}
if (49999 == i) {
NSLog(@"后面的任务%d完成 %@",n,[NSThread currentThread]);
}
}
});
}
NSLog(@"有没有阻塞线程 %@",[NSThread currentThread]);
}
屏幕快照 2019-01-01 下午4.34.06.png
队列组和栅栏的组合
- (IBAction)sender7:(UIButton *)sender {
// 队列组合栅栏的组合
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
for (int n = 0; n<3; n++) {
NSLog(@"1队列组%d %@",n,[NSThread currentThread]);
}
});
dispatch_barrier_async(queue, ^{
NSLog(@"这行barrier1");
});
dispatch_group_async(group, queue, ^{
for (int n = 0; n < 3; n++) {
NSLog(@"2队列组 %d %@",n,[NSThread currentThread]);
}
});
dispatch_barrier_async(queue, ^{
NSLog(@"执行barrier2");
});
dispatch_group_notify(group, queue, ^{
NSLog(@"队列组的通知");
});
NSLog(@"有没有阻塞线程%@",[NSThread currentThread]);
}
屏幕快照 2019-01-01 下午5.03.38.png
信号量
- (IBAction)sender8:(UIButton *)sender {
// 信号量
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int n = 0; n < 5; n++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"前面的异步操作%d 线程 %@",n,[NSThread currentThread]);
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
for (int n = 0; n < 3; n++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"后面的异步操作%d 线程%@",n,[NSThread currentThread]);
});
}
NSLog(@"有没有阻塞主线程%@",[NSThread currentThread]);
}
屏幕快照 2019-01-02 上午9.16.28.png
死锁主线程
- (IBAction)sender9:(UIButton *)sender {
// 死锁主线程
NSLog(@"线程之前 %@",[NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"同步操作的线程 %@",[NSThread currentThread]);
});
NSLog(@"线程之后 %@",[NSThread currentThread]);
}
分析结论:只打印了一句,发现后面两个没打印出来,说明已经死锁了。我们来一步一步分析,打印完第一句后,同步操作dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中,然后 main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死
屏幕快照 2019-01-02 上午9.35.11.png
阻塞子线程
- (IBAction)sender10:(UIButton *)sender {
// 死锁子线程
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);
NSLog(@"之前线程 - %@", [NSThread currentThread]);
dispatch_async(myQueue, ^{
NSLog(@"同步操作之前线程 - %@", [NSThread currentThread]);
dispatch_sync(myQueue, ^{
NSLog(@"同步操作时线程 - %@", [NSThread currentThread]);
});
NSLog(@"同步操作之后线程 - %@", [NSThread currentThread]);
});
NSLog(@"之后线程 - %@", [NSThread currentThread]);
// 分析结论:打印第一句之后就是一个异步操作,异步操作会另外开辟线程,2个线程分别打印了最后一句和第二句,当执行到同步操作dispatch_sync时立马阻塞当前线程,一直等到 sync 里的任务执行完才会继续往下。于是 sync 就把自己 Block 中的任务放到 queue 中,可 queue 是一个串行队列,一次执行一个任务,所以 sync 的 Block 必须等到前一个任务执行完毕,可是 queue 正在执行的任务就是被 sync 阻塞了的那个。于是又发生了死锁。所以 sync 所在的线程被卡死了。剩下的两句代码自然不会打印。
}
屏幕快照 2019-01-02 下午3.26.51.png