多线程的运用

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
上一篇下一篇

猜你喜欢

热点阅读