线程(Thread)基础知识
现代的操作系统,包括iOS,都支持线程Thread的概念,每个进程可以包含多个线程,借助多个CPU的内核,可以同时处理多个任务。即便是在早期单核CPU的时代,操作系统也可以把CPU资源在多个线程之间进行切换,给用户的感觉是多个任务在“同时”处理。
进程与线程
每个应用程序都有一个进程,例如在Mac系统中,可以通过活动监视器来查看当前Mac电脑正在运行的进程。每个进程可以包含多个线程,这些线程可以同时运行,并各自处理一些任务。早期的CPU只有一个核心,因此会交替处理各个线程中的任务,让用户产生一种多任务同时处理的“感觉”。当CPU拥有多个内核时,各个线程就可以分配到不同的CPU内核中进行处理,即为真正意义上的多任务同时处理。
对于任意一个iOS应用,程序运行起来后,默认会产生一个主线程(MainThread),主线程专门用来处理UIKit对象的操作,如界面的显示与更新、处理用户交互事件等等。(请牢牢记忆这点,所有与UI相关的操作都要在主线程中进行)
对于一个App应用来说,之所以需要引入多个线程,很大程度上是由于存在一些操作是非常耗时的,例如:发送网络请求并等待服务器的响应,这种耗时操作是不能够放在主线程中进行操作的,因为在等待的时间内,主线程被使用,用户是不能做任何交互动作的,因而会极大影响用户体验。对于耗时的操作,需要再另外创建一个线程,放到后台处理,当处理完成得到结果后,再返回主线程去设置UI界面,这就涉及到线程间通信的相关知识。
多线程同时处理任务,还会涉及到线程安全(thread-safe)的问题,当多个线程对一个对象进行同时操作时,就会影响结果的正确性。因此,线程对某个对象操作时,需要使用到“锁”的机制,即当一个线程操作一个对象的过程中,会给这个对象上锁,其他线程就不能够访问该对象了。加锁虽然解决了线程安全的问题,但带来的另外一个弊端就是影响了程序运行的效率。
当我们给一个自定义类中添加属性的时候,属性关键字其中就有:atomic和nonatomic的区分,其中:atomic是线程安全的,当有线程访问这个属性时,会为该属性的setter方法加锁,atomic是默认值。但是,我们在实际的开发中,都会把给属性设置nonatomic关键字,因为对于移动设备来说,效率更加重要,但也需要程序员注意线程安全问题。
NSThread类
NSThred类是苹果提供的管理线程的类,提供了一些线程管理的方法。但是随着GCD和NSOperation的推出,NSThread的使用场景已经大大减少。在实际的开发中,偶尔会使用NSThread类来获取一些线程信息。常用的一些方法如下:
- 获取当前线程对象
+ (NSThread *)currentThread;
- 获取主线程对象
+ (NSThread *)mainThread;
- 使主线程休眠ti秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
示例代码
下方的示例代码中,点击【显示内容】按钮,会对3个Label上显示的文字进行设置,每个label上显示的文字,都是从一个方法中获取。但在获取文字的方法实现中,都会对主线程进行阻塞3秒,在阻塞的过程中,用户是无法进行任何操作的,除了点击Home键退出应用。
- 实现获取字符串的方法,在每个方法中都会阻塞主线程3秒;
-(NSString *) generateString1{
//阻塞主进程
[NSThread sleepForTimeInterval:3.0];
NSString *string = @"hello world!";
return string;
}
-(NSString *) generateString2{
//阻塞主进程
[NSThread sleepForTimeInterval:3.0];
NSString *string = @"www.99iOS.com!";
return string;
}
-(NSString *) generateString3{
//阻塞主进程
[NSThread sleepForTimeInterval:3.0];
NSString *string = @"2017!";
return string;
}
- 实现【显示内容】按钮的点击操作。
- (IBAction)showContent:(id)sender {
//记录开始时间
NSLog(@"\n Start Time:%@, \n Current Thread: %@, \n Main Thread: %@", [NSDate date], [NSThread currentThread], [NSThread mainThread]);
self.label1.text = [self generateString1];
self.label2.text = [self generateString2];
self.label3.text = [self generateString3];
//记录结束时间
NSLog(@"\n End Time:%@, \n Current Thread: %@, \n Main Thread: %@", [NSDate date], [NSThread currentThread], [NSThread mainThread]);
}
运行结果如下。我们可以看到程序执行的时间总共约有9秒钟,并且都是在主线程中执行(线程ID = 1),在运行期间,按钮是不能够被点击的。
示例代码
最后编辑时间为: September 13th , 2017 at 03:08 pm
本文由 99ios 创作,转载请注明出处