文章分享至个人我的技术博客: cainrun.github.io/15020181423…html
前面咱们已经把经常使用的GCD
, NSOperation
, NSOperationQueue
讲完了, 如今咱们继续来看看, 另外一个不经常使用的多线程(实际上是我本身不经常使用), 它就是NSThread
.git
说到NSThread
的话, 我么那就不得不提到它的底层叫作Pthread
, 这是一个由C
语言写的多线程技术, 能够在Unix
, Linux
和Windows
上使用.github
但因为是用C
语言所写的, 因此须要本身管理线程生命周期, 开发难度比较大(不得不佩服一下搞C
语言的大佬们), 这里咱们简单了解一下就行了, 想深刻了解的话, 能够自行去谷歌一下.vim
转载声明:如须要转载该文章, 请联系做者, 而且注明出处, 以及不能擅自修改本文.安全
这里引用一段来自维基百科
的Pthread介绍:微信
POSIX
线程(英语:POSIX Threads
,常被缩写为Pthreads
)是POSIX
的线程标准,定义了建立和操纵线程的一套API
。多线程实现
POSIX
线程标准的库常被称做Pthreads
,通常用于Unix-like POSIX
系统,如Linux
、Solaris
。框架可是
Microsoft Windows
上的实现也存在,例如直接使用Windows API
实现的第三方库pthreads-w32
;函数而利用
Windows
的SFU/SUA
子系统,则可使用微软提供的一部分原生POSIX API
。性能
在举例子🌰以前, 咱们得分析一下使用Pthread
的几个步骤:
#import <pthread.h>
- (void)cratePthread {
pthread_t thread;
pthread_create(&thread, NULL, run, NULL);
}
void *run(void *param) {
NSLog(@"执行任务, 当前的线程为: %@", [NSThread currentThread]);
return NULL;
}复制代码
2017-08-06 20:33:42.496 NSThread-Example[4008:314745] 执行任务, 当前的线程为: <NSThread: 0x60800007cb40>{number = 3, name = (null)}复制代码
这里要解释一下pthread_create(&thread, NULL, run, NULL)
括号里的四个属性:
&
号加线程对象名.run
其实就是咱们以前讲到的任务.NSThread
是苹果爸爸针对Pthread
而封装的Objective-C
对象, 有啥好处?
Pthread
管理线程生命周期代码.以前咱们常常看到[NSThread currentThread]
这句代码, 就是获取当前线程信息的.
如今咱们来看看NSThread
的简单使用:
- (void)nsthread {
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(runTheThread)
object:nil];
[thread start];
}
- (void)runTheThread {
NSLog(@"执行任务, 当前的线程为: %@", [NSThread currentThread]);
}复制代码
2017-08-06 20:53:32.129 NSThread-Example[4108:332154] 执行任务, 当前的线程为: <NSThread: 0x600000265900>{number = 3, name = (null)}复制代码
除此以外, 咱们还能够在建立隐式线程并启动它:
- (void)backgroundThread {
[self performSelectorOnMainThread:@selector(runTheBackgroundThread)
withObject:nil
waitUntilDone:YES];
}
- (void)runTheBackgroundThread {
NSLog(@"执行任务, 当前的线程为: %@", [NSThread currentThread]);
}复制代码
2017-08-06 20:57:35.971 NSThread-Example[4159:338649] 执行任务, 当前的线程为: <NSThread: 0x608000067300>{number = 1, name = main}复制代码
获取主线程
+ (NSThread *)mainThread;复制代码
上面有获取主线程咯, 那这里也有一个判断是不是主线程的方法了, 区别在于, 一个是实例方法, 一个是类方法:
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
@property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main复制代码
还有咱们以前常常看到的获取线程方法:
@property (class, readonly, strong) NSThread *currentThread;
[NSThread currentThread];复制代码
若是你想和GCD
那样设置线程的名字或者是获取线程的名字, 那么你能够用这个:
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);复制代码
在上面的代码里, 咱们能够看到和NSOperation
同样, 有一个- (void)start
方法, 用途是同样的, 就是启动线程:
- (void)start NS_AVAILABLE(10_5, 2_0);复制代码
除了这个以外还有暂停当前线程的方法:
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;复制代码
最后还有一个终止当前线程的方法和取消当前线程的方法:
+ (void)exit;
- (void)cancel NS_AVAILABLE(10_5, 2_0);复制代码
既然这里提到了操控线程的状态, 那就得讲讲, 线程状态的切换.
当咱们用NSThread
建立一条信线程的时候, 内存中会占用一块内存, 以下图:
一旦咱们经过调用- (void)start
以后, 就会把当前的线程对象, 加入到线程池中, 以下图:
若是还有其余线程对象添加进来或者是其余线程, 就会以下图所示:
这里举几个线程切换状态时的几个例子:
CPU
去调用当前线程对象的时候, 那么当前线程就会进入一个运行状态
, 不然就是准备就绪状态
(好比CPU
去调用其余线程对象), 以下图:CPU
在运行当前线程对象的时候调用sleep方法
或者是同步锁
, 那么当前线程就会进入一个线程阻塞状态
, 等到sleep方法
到时间以后, 或者获得同步锁
, 就会回到就绪状态
.CPU
在运行当前线程对象的时候, 任务执行完成或者是强制退出, 那么当前线程对象就会进入一个终止状态
.虽然经过苹果爸爸封装的NSThread
或者是用C
写的Pthread
能够更加直接的操做线程, 但咱们通常不会直接用到NSThread
和Pthread
去操做线程.
直接操做线程的话能够一不当心就GG
了, 什么意思呢?
好比咱们在一个大项目里直接操做了线程, 给你个8核CPU
, 咱们为了彻底使用CPU
的性能, 可能会建立8
条, 或者是16
条线程, 然而在咱们代码调用的框架里, 又作了相似的操做(代码不会知道咱们建立了线程), 那么这时候就会形成上百条, 上千条线程了.
其实代码自己是没有问题的, 但因为咱们的操做不当, 最终就出现了问题, 使用线程都会有消耗一些内存和内核资源, 因此为了安全起见, 仍是不要直接操做线程了.
项目地址: github.com/CainRun/iOS…