面試題
1.你理解的多線程?
2.ios的多線程方案有哪幾種?你更傾向于哪一種?
3.你在項(xiàng)目中用過GCD?
4.GCD的隊(duì)列類型
5.說一下OperationQueue和GCD的區(qū)別、以及各自的優(yōu)勢(shì)
6.線程安全的處理手段有哪些?
7.OC你了解的鎖有哪些?
- 自旋和互斥對(duì)比?
- 使用以上鎖需要注意哪些?
- 用C/OC/C++,任選其一,實(shí)現(xiàn)自旋或互斥?
下面我們來看看幾個(gè)例子
代碼詳見 gitHub_Demo
例1
#import "ViewController_1.h"
@interface ViewController_1 ()
@end
@implementation ViewController_1
- (void)viewDidLoad {
[super viewDidLoad];
//這句代碼的本質(zhì)是往Runloop中添加定時(shí)器 如果在主線程,runloop自動(dòng)開啟好了的
[self performSelector:@selector(test1) withObject:nil afterDelay:.0];//afterDelay-->異步執(zhí)行的 主隊(duì)列
//主隊(duì)列異步執(zhí)行時(shí),會(huì)先執(zhí)行完主線程上的代碼,然后在主線程上順序執(zhí)行任務(wù),不會(huì)有新的線程產(chǎn)生,所有任務(wù)都是在主線程上完成的
NSLog(@"%@",[NSThread currentThread]);
sleep(1);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
sleep(2);
NSLog(@"asyncThread--%@",[NSThread currentThread]);
NSLog(@"1");
//如果是子線程需要自己手動(dòng)去啟動(dòng)runloop
[self performSelector:@selector(test) withObject:nil afterDelay:.0];
//手動(dòng)去啟動(dòng)runloop
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
NSLog(@"3");
});
NSLog(@"4");
}
-(void)test{
NSLog(@"2");
}
-(void)test1{
NSLog(@"test1Thread---%@",[NSThread currentThread]);
NSLog(@"test1");
}
@end
打?。?沒有手動(dòng)去啟動(dòng)runloop
Multithreading[17114:917201] <NSThread: 0x600000501400>{number = 1, name = main}
Multithreading[17114:917201] 4
Multithreading[17114:917201] test1Thread---<NSThread: 0x600000501400>{number = 1, name = main}
Multithreading[17114:917201] test1
Multithreading[17114:917255] asyncThread--<NSThread: 0x6000005825c0>{number = 3, name = (null)}
Multithreading[17114:917255] 1
Multithreading[17114:917255] 3
=========================================
手動(dòng)去啟動(dòng)runloop
Multithreading[17130:918365] <NSThread: 0x600000ef1400>{number = 1, name = main}
Multithreading[17130:918365] 4
Multithreading[17130:918365] test1Thread---<NSThread: 0x600000ef1400>{number = 1, name = main}
Multithreading[17130:918365] test1
Multithreading[17130:918422] asyncThread--<NSThread: 0x600000e712c0>{number = 3, name = (null)}
Multithreading[17130:918422] 1
Multithreading[17130:918422] 2
Multithreading[17130:918422] 3
例2
- (void)test{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1"); //一完成任務(wù)之后,子線程就退出了
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
NSLog(@"===End====");
}
運(yùn)行結(jié)果:NSLog(@"1") 之后 崩潰了

Multithreading_01.png
- (void)test{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1");
//一完成任務(wù)之后,子線程就退出了
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:NO];
sleep(2);
NSLog(@"===End====");
}
打印:
Multithreading[19178:1044135] 1
Multithreading[19178:1043871] ===End====

Multithreading_02.png
修改崩潰:
- (void)test{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1");
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
sleep(2);
NSLog(@"===End====");
}
打印:
Multithreading[19214:1046668] 1
Multithreading[19214:1046668] 2
Multithreading[19214:1046548] ===End====
【開啟了runloop后,延長了子線程的生命】
【如果沒有,則會(huì)執(zhí)行完任務(wù)子線程就退出了】
iOS中的常見多線程方案

Multithreading_03.png
GCD的常用函數(shù)

Multithreading_04.png
GCD的隊(duì)列

Multithreading_05.png
//異步開啟子線程,執(zhí)行任務(wù)
-(void)test1{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊(duì)列
dispatch_async(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
// <NSThread: 0x6000033da280>{number = 3, name = (null)}
});
}
//同步,在當(dāng)前線程執(zhí)行任務(wù)
-(void)test2{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊(duì)列
dispatch_sync(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
// <NSThread: 0x600002442c80>{number = 1, name = main}
});
}
//同步,在當(dāng)前線程執(zhí)行任務(wù)(并發(fā)無效 )
-(void)test3{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊(duì)列
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)1:%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務(wù)1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600002b66980>{number = 1, name = main}
*/
}
//異步,開啟新線程執(zhí)行任務(wù)(并發(fā))
-(void)test4{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊(duì)列
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務(wù)1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
*/
}
//串行隊(duì)列異步執(zhí)行任務(wù) (按順序執(zhí)行)
-(void)test5{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊(duì)列
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務(wù)1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務(wù)2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
*/
}
//在當(dāng)前線程(此時(shí)是主線程),串行執(zhí)行任務(wù)
-(void)test6{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊(duì)列
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)1:%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務(wù)1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600000c69400>{number = 1, name = main}
*/
}
//主隊(duì)列里面異步執(zhí)行(此時(shí)沒有開啟新的線程)
-(void)test7{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務(wù)2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務(wù)1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務(wù)2:<NSThread: 0x600003d7d400>{number = 1, name = main}
*/
}
容易混淆的術(shù)語

Multithreading_06.png
dispatch_sync和dispatch_async用來控制是否要開啟新的線程
隊(duì)列的類型,決定了任務(wù)的執(zhí)行方式(并發(fā)、串行)
1.并發(fā)隊(duì)列
2.串行隊(duì)列
3.主隊(duì)列(也是一個(gè)串行隊(duì)列)
注意:異步的它不一定 要開啟新的線程(只是具備開啟新的線程的能力)
主隊(duì)列里面異步執(zhí)行任務(wù)
只要是sync(同步),或者是在主隊(duì)列里,他就是在當(dāng)前線程里面執(zhí)行任務(wù),那它一定是串行執(zhí)行任務(wù)
沒有開啟新的線程,那它肯定是串行 執(zhí)行任務(wù)的
各種隊(duì)列的執(zhí)行效果

Multithreading_07.png
總結(jié):

Multithreading_08.png
友情鏈接: