面試題
1.你理解的多線程?
2.ios的多線程方案有哪幾種恕洲?你更傾向于哪一種?
3.你在項目中用過GCD?
4.GCD的隊列類型
5.說一下OperationQueue和GCD的區(qū)別盐碱、以及各自的優(yōu)勢
6.線程安全的處理手段有哪些楼誓?
7.OC你了解的鎖有哪些玉锌?
- 自旋和互斥對比?
- 使用以上鎖需要注意哪些疟羹?
- 用C/OC/C++主守,任選其一,實現(xiàn)自旋或互斥榄融?
下面我們來看看幾個例子
代碼詳見 gitHub_Demo
例1
#import "ViewController_1.h"
@interface ViewController_1 ()
@end
@implementation ViewController_1
- (void)viewDidLoad {
[super viewDidLoad];
//這句代碼的本質是往Runloop中添加定時器 如果在主線程参淫,runloop自動開啟好了的
[self performSelector:@selector(test1) withObject:nil afterDelay:.0];//afterDelay-->異步執(zhí)行的 主隊列
//主隊列異步執(zhí)行時,會先執(zhí)行完主線程上的代碼愧杯,然后在主線程上順序執(zhí)行任務涎才,不會有新的線程產生,所有任務都是在主線程上完成的
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");
//如果是子線程需要自己手動去啟動runloop
[self performSelector:@selector(test) withObject:nil afterDelay:.0];
//手動去啟動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
打用裥А:
沒有手動去啟動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
=========================================
手動去啟動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"); //一完成任務之后憔维,子線程就退出了
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
NSLog(@"===End====");
}
運行結果:NSLog(@"1") 之后 崩潰了
Multithreading_01.png
- (void)test{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1");
//一完成任務之后,子線程就退出了
}];
[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后,延長了子線程的生命】
【如果沒有舒萎,則會執(zhí)行完任務子線程就退出了】
iOS中的常見多線程方案
Multithreading_03.png
GCD的常用函數(shù)
Multithreading_04.png
GCD的隊列
Multithreading_05.png
//異步開啟子線程程储,執(zhí)行任務
-(void)test1{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
dispatch_async(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
// <NSThread: 0x6000033da280>{number = 3, name = (null)}
});
}
//同步,在當前線程執(zhí)行任務
-(void)test2{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
dispatch_sync(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
// <NSThread: 0x600002442c80>{number = 1, name = main}
});
}
//同步臂寝,在當前線程執(zhí)行任務(并發(fā)無效 )
-(void)test3{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600002b66980>{number = 1, name = main}
*/
}
//異步章鲤,開啟新線程執(zhí)行任務(并發(fā))
-(void)test4{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //全局并發(fā)隊列
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
執(zhí)行任務1:<NSThread: 0x6000018ac740>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x6000018ac4c0>{number = 4, name = (null)}
*/
}
//串行隊列異步執(zhí)行任務 (按順序執(zhí)行)
-(void)test5{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊列
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務1:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
執(zhí)行任務2:<NSThread: 0x600002de93c0>{number = 3, name = (null)}
*/
}
//在當前線程(此時是主線程),串行執(zhí)行任務
-(void)test6{
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); //串行隊列
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600000c69400>{number = 1, name = main}
*/
}
//主隊列里面異步執(zhí)行(此時沒有開啟新的線程)
-(void)test7{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務1:%@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for(int i=0;i<5;i++){
NSLog(@"執(zhí)行任務2:%@",[NSThread currentThread]);
}
});
/*
執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務1:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
執(zhí)行任務2:<NSThread: 0x600003d7d400>{number = 1, name = main}
*/
}
容易混淆的術語
Multithreading_06.png
dispatch_sync和dispatch_async用來控制是否要開啟新的線程
隊列的類型咆贬,決定了任務的執(zhí)行方式(并發(fā)败徊、串行)
1.并發(fā)隊列
2.串行隊列
3.主隊列(也是一個串行隊列)
注意:異步的它不一定 要開啟新的線程(只是具備開啟新的線程的能力)
主隊列里面異步執(zhí)行任務
只要是sync(同步),或者是在主隊列里掏缎,他就是在當前線程里面執(zhí)行任務皱蹦,那它一定是串行執(zhí)行任務
沒有開啟新的線程,那它肯定是串行 執(zhí)行任務的
各種隊列的執(zhí)行效果
Multithreading_07.png
總結:
Multithreading_08.png
友情鏈接: