https://blog.csdn.net/PeaksLee/article/details/78270157
- NSThread
- GCD
- NSOperation & NSOperationQueue
1. NSThread
苹果封装, 完全面向对象。但生命周期需要手动管理.
--------------------------------------
////先创建再启动//////////////////////
--------------------------------------
OBJECTIVE-C
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
SWIFT
//创建
let thread = NSThread(target: self, selector: "run:", object: nil)
//启动
thread.start()
--------------------------------------
////创建并自动启动//////////////////////////
--------------------------------------
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
NSThread.detachNewThreadSelector("run:", toTarget: self, withObject: nil)
--------------------------------------
////使用 NSObject 的方法创建并自动启动////////////
--------------------------------------
@interface NSObject (NSThreadPerformAdditions)
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@end
///////////////////////////////////////////////////
OBJECTIVE-C
[self performSelectorInBackground:@selector(run:) withObject:nil];
SWIFT
苹果认为 performSelector: 不安全所以在Swift 去掉了这个方法。
其他方法.............不一一列举了。。
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
2. GCD
苹果为多核的并行提出的解决方案,
合理地利用更多的CPU内核(比如双核、四核),
自动管理线程的生命周期(创建线程、调度任务、销毁线程),
使用的是 c语言,利用了 Block(Swift里叫做闭包),
使用起来更加方便灵活。
GCD 中加入了两个非常重要的概念: 任务 和 队列
任务:
即操作 你想要干什么,就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。
任务有两种执行方式: 同步执行 和 异步执行
区别:
是否会创建新的线程。
会不会阻塞当前线程,直到 Block 中的任务执行完毕!
同步(sync) 操作,会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
异步(async)操作,当前线程会直接往下执行,不会阻塞当前线程。
队列:用于存放任务。 串行队列 并行队列。
串行队列的任务: GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
并行队列的任务: GCD 也会 FIFO的取出来,但不同的是它取出来一个就会放到别的线程,再取出来一个又放到另一个的线程。这样由于取的动作很快,看起来所有的任务是一起执行的。需要注意GCD 会根据系统资源控制并行的数量,所以如果任务很多它并不会让所有任务同时执行。
创建队列
主队列:这是一个特殊的 串行队列。它用于刷新 UI,
任何需要刷新 UI 的工作都要在主队列执行,
一般耗时的任务都要放到别的线程执行。
//OBJECTIVE-C
dispatch_queue_t queue = ispatch_get_main_queue();
//SWIFT
let queue = ispatch_get_main_queue()
自己创建的队列: 串行 并行
它有两个参数,第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。第二个才是最重要的。
第二个参数用来表示创建的队列是串行的还是并行的,
DISPATCH_QUEUE_SERIAL 或 NULL 创建串行队列。
DISPATCH_QUEUE_CONCURRENT 创建并行队列。
//OBJECTIVE-C
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
//SWIFT
//串行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", nil);
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL)
//并行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)
全局并行队列:
只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//SWIFT
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
创建任务
同步任务: 阻塞当前线程 (SYNC)
OBJECTIVE-C
dispatch_sync(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_sync(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
异步任务:不会阻塞当前线程 (ASYNC)
OBJECTIVE-C
dispatch_async(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
SWIFT
dispatch_async(<#queue#>, { () -> Void in
//code here
println(NSThread.currentThread())
}
为更好的理解 同步,异步,和各种队列的使用,看两个示例:
示例一:
以下代码在主线程调用,结果是什么?
NSLog("之前 - %@", NSThread.currentThread())
dispatch_sync(dispatch_get_main_queue(), { () -> Void in
NSLog("sync - %@", NSThread.currentThread())
})
NSLog("之后 - %@", NSThread.currentThread())
答案:
只会打印第一句:之前 - <NSThread: 0x7fb3a9e16470>{number = 1, name = main} ,然后主线程就卡死了,你可以在界面上放一个按钮,你就会发现点不了了。
解释:
同步任务会阻塞当前线程,然后把 Block 中的任务放到指定的队列中执行,只有等到 Block 中的任务完成后才会让当前线程继续往下运行。
那么这里的步骤就是:打印完第一句后,dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中,可是 main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。
示例二:
以下代码会产生什么结果?
let queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL)
NSLog("之前 - %@", NSThread.currentThread())
dispatch_async(queue, { () -> Void in
NSLog("sync之前 - %@", NSThread.currentThread())
dispatch_sync(queue, { () -> Void in
NSLog("sync - %@", NSThread.currentThread())
})
NSLog("sync之后 - %@", NSThread.currentThread())
})
NSLog("之后 - %@", NSThread.currentThread())
未完 待续。。。
网友评论