iOS-多线程编程学习之NSThread(三)

  一个NSThread对象控制一个线程的执行。使用这个类你可以在线程中执行自定义的OC方法。当你需要执行长任务时使用线程是非常好的方式,它可以避免需要执行事件处理和UI更新的主线程被阻塞。此外,线程还可以通过把大任务划分为更小的任务在多线程中进行处理,这种方式在多核计算机中可以显著提升性能。

  在OS X v10.5之前,只能通过detachNewThreadSelector: toTarget: withObject:这个类方法来创建一个新线程来执行某个方法。而在OS X v10.5之后,可以创建一个NSThread类的实例,并通过发送start消息来启动一个线程。
  NSThread提供了和NSOperation类似的语法来进行线程运行时控制。你可以取消一个线程的执行,决定线程是否还需要继续执行或结束线程任务。取消线程需要手动进行管理。

创建线程的方式

创建线程主要有三种方式。

第一种:先创建NSThread的实例,然后再启动线程。这又称为动态创建方式。

//创建一个线程实例
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
//启动线程
[thread start];

第二种:直接创建并启动线程。这个即OS X v10.5前支持的方式,又称静态创建方式。

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

第三种方式:隐式的创建并启动线程。本质是通过NSObject类的实力方法performSelectorInBackground: withObject:创建一个后台线程执行特定方法的。NSObject中还有类似的方法指定在主线程或某个特定线程上执行方法。

[self performSelectorInBackground:@selector(run) withObject:nil];

比较

  方法二和方法三的优点就是快捷,适合于不需要太多线程控制的短任务。
  方法一最大的优点就是可以轻松获取线程对象。通过该对象引用可以手动管理线程的状态,而且还方便线程间通信的实现。

自定义NSThread子类

  正如上面所说的,现在已经支持继承NSThread实现他的子类。所以这次将继承NSThread实现自定义的子类,通过重写main方法实现来处理县城任务。

LYSThread.h //声明自定义子类继承于NSThread

#import <Foundation/Foundation.h>

@interface LYSThread : NSThread
@end

LYSThread.m //重写main方法

#import "LYSThread.h"

@implementation LYSThread

//重写main方法,执行任务
-(void)main
{
    [self setName:@"LYSThread"];
    for (int i = 0; i < 100; i++) {
        NSLog(@"%zd ===> %@", i, [NSThread currentThread]);
    }
}

@end

取消和退出线程

退出

NSThread类中有一个方法用于终止线程。

+ (void)exit

  这个方法需要先使用currentThread类方法获取当前执行的线程。在线程退出前,该方法会向默认消息中心(Default notification center)发出一个NSThreadWillExitNotification消息。由于notifications的消息是异步分发的,所以所有注册到该消息中的观察者都将收到这个线程即将退出的消息。
  但是我们应该尽量避免调用这个方法终止线程,因为这样线程将没有机会去清理执行期间分配的那些资源了。

取消

  NSThread类中提供了一个方法修改线程状态为取消状态,暗示线程应该终止。

- (void)cancel

  这个方法的语义和NSOperation对象的操作是类似的。这个方法会改变线程的状态信息,通过调用isCancleled获取状态信息的话就可以看到这个方法的作用了。支持取消操作的线程应该先调用isCancelled查看线程当前状态是否已是取消状态,或者是否线程是否已终止。

扩展

线程权值

  线程可以设置权值,为0~1.0的double类型值,其中1.0为权值最高。权值越高的线程将会更频繁的获取系统资源执行任务。

[thread setThreadPriority:1.0f];

线程休眠

线程休眠主要有两个方法。两个都是NSThread类的类方法。

第一个方法是让线程休眠直到指定时间。

[NSThread sleepUntilDate:[NSDate new]];

第二个方法是设置睡眠的时间。

//设置休眠2秒
[NSThread sleepForTimeInterval:2.0f];

主线程

获取主线程的NSThread对象。

NSThread *mainThread = [NSThread mainThread];

判断是否是主线程。

//+ (BOOL)isMainThread
[NSThread isMainThread];

获取当前线程

NSThread还提供了方法获取当前执行的线程的NSThread对象。

NSThread *thread = [NSThread currentThread];

判断线程执行状态

线程是否正在执行。

//正在执行返回YES,否则返回NO
if([thread isExecuting])
    NSLog(@"Thread is excuting.");

线程是否已经完成执行。

//已完成返回YES,否则返回NO
if([thread isFinished])
    NSLog(@"Thread is finished.");

线程是否取消。

//已取消返回YES,否则返回NO
if([thread isCancelled])
    NSLog(@"Thread is cancelled.");

Demon源代码

这里给出Github项目上的源代码。
传送门:Github-iOS_Framework_study-ThreadDemon

参考资料

  1. 苹果官方文档-NSThread
  2. iOS开发–四种多线程技术方案
  3. 谈iOS多线程(NSThread、NSOperation、GCD)编程