iOS底层学习-day-19
前言-OC-多线程篇
我是一名iOS开发者, iOS底层 菜鸟的进阶之路30天。
runloop常驻线程-封装
OC封装
- MJPermenantThread.h
#import <Foundation/Foundation.h>
typedef void (^MJPermenantThreadTask)(void);
@interface MJPermenantThread : NSObject
/**
开启线程
*/
//- (void)run;
/**
在当前子线程执行一个任务
*/
- (void)executeTask:(MJPermenantThreadTask)task;
/**
结束线程
*/
- (void)stop;
@end
- MJPermenantThread.m
#import "MJPermenantThread.h"
/** MJThread **/
@interface MJThread : NSThread
@end
@implementation MJThread
- (void)dealloc {
NSLog(@"%s", __func__);
}
@end
/** MJPermenantThread **/
@interface MJPermenantThread ()
@property (strong, nonatomic) MJThread *innerThread;
@property (assign, nonatomic, getter=isStopped) BOOL stopped;
@end
@implementation MJPermenantThread
#pragma mark - public methods
- (instancetype)init {
if (self = [super init]) {
self.stopped = NO;
__weak typeof(self) weakSelf = self;
self.innerThread = [[MJThread alloc] initWithBlock:^{
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.isStopped) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}];
[self.innerThread start];
}
return self;
}
//- (void)run
//{
// if (!self.innerThread) return;
//
// [self.innerThread start];
//}
- (void)executeTask:(MJPermenantThreadTask)task {
if (!self.innerThread || !task) return;
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}
- (void)stop {
if (!self.innerThread) return;
[self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self stop];
}
#pragma mark - private methods
- (void)__stop {
self.stopped = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
- (void)__executeTask:(MJPermenantThreadTask)task {
task();
}
@end
C封装
/** MJPermenantThread **/
@interface MJPermenantThread()
@property (strong, nonatomic) MJThread *innerThread;
@end
@implementation MJPermenantThread
#pragma mark - public methods
- (instancetype)init {
if (self = [super init]) {
self.innerThread = [[MJThread alloc] initWithBlock:^{
NSLog(@"begin----");
// 创建上下文(要初始化一下结构体)
CFRunLoopSourceContext context = {0};
// 创建source
CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
// 往Runloop中添加source
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
// 销毁source
CFRelease(source);
// 启动
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);
// while (weakSelf && !weakSelf.isStopped) {
// // 第3个参数:returnAfterSourceHandled,设置为true,代表执行完source后就会退出当前loop
// CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
// }
NSLog(@"end----");
}];
[self.innerThread start];
}
return self;
}
//- (void)run
//{
// if (!self.innerThread) return;
//
// [self.innerThread start];
//}
- (void)executeTask:(MJPermenantThreadTask)task {
if (!self.innerThread || !task) return;
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}
- (void)stop {
if (!self.innerThread) return;
[self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self stop];
}
#pragma mark - private methods
- (void)__stop {
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
- (void)__executeTask:(MJPermenantThreadTask)task {
task();
}
@end
多线程-GCD
GCD 2个用来执行任务的函数dispatch_sync - dispatch_async
-
用同步的方式执行任务//就是在当前线程做事情
- dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
- queue:队列
- block:任务
-
用异步的方式执行任务
- dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD的队列可以分为2大类型
-
并发队列(Concurrent Dispatch Queue)
- 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
- 并发功能只有在异步(dispatch_async)函数下才有效
-
串行队列(Serial Dispatch Queue)
- 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
GCD有4个术语比较容易混淆:同步、异步、并发、串行
-
同步和异步主要影响:能不能开启新的线程
- 同步:在当前线程中执行任务,不具备开启新线程的能力
- 异步:在新的线程中执行任务,具备开启新线程的能力
-
并发和串行主要影响:任务的执行方式
- 并发:多个任务并发(同时)执行
- 串行:一个任务执行完毕后,再执行下一个任务
GCD的一写判断线程是否死锁
- dispatch_sync和dispatch_async用来控制是否要开启新的线程
- 队列的类型,决定了任务的执行方式(并发、串行)
- 并发队列
- 串行队列
- 主队列(也是一个串行队列)
- 队列的类型,决定了任务的执行方式(并发、串行)
- 例子1 - 以下代码是在主线程执行的,会不会产生死锁?会!
- (void)interview01 {
// 以下代码是在主线程执行的,会不会产生死锁?会!
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"执行任务2");
});
NSLog(@"执行任务3");
// 在sync中,往当前的串行队列中添加任务会死锁
}
- 例子2 - 以下代码是在主线程执行的,会不会产生死锁?不会!
- (void)interview02 {
// 以下代码是在主线程执行的,会不会产生死锁?不会!
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"执行任务2");
});
NSLog(@"执行任务3");
// 执行任务1 > 执行任务3 > 执行任务2
}
- 例子3 - 以下代码是在主线程执行的,会不会产生死锁?会!
- (void)interview03 {
// 以下代码是在主线程执行的,会不会产生死锁?会!
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{ // 0
NSLog(@"执行任务2");
dispatch_sync(queue, ^{ // 1要等 0执行完,再执行执行任务3
NSLog(@"执行任务3");
});
NSLog(@"执行任务4");
});
NSLog(@"执行任务5");
// 1 > 5 > 2 > 死锁
}
- 例子4 - 以下代码是在主线程执行的,会不会产生死锁?不会!
- (void)interview04 {
// 以下代码是在主线程执行的,会不会产生死锁?不会!
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
// dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_CONCURRENT);//不会
dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_SERIAL);//不会
dispatch_async(queue, ^{ // 0
NSLog(@"执行任务2");
dispatch_sync(queue2, ^{ // 1
NSLog(@"执行任务3");
});
NSLog(@"执行任务4");
});
NSLog(@"执行任务5");
// 1 > 5 > 2 > 3 > 4
}
- 例子5 - 以下代码是在主线程执行的,会不会产生死锁?不会!
- (void)interview05 {
// 以下代码是在主线程执行的,会不会产生死锁?不会!
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{ // 0
NSLog(@"执行任务2");
dispatch_sync(queue, ^{ // 1
NSLog(@"执行任务3");
});
NSLog(@"执行任务4");
});
NSLog(@"执行任务5");
// 1 > 5 > 2 > 3 > 4
}