iOS多线程

线程和进程

一般而言进程包含如下3个特征:

  • 独立性:进程是系统中独立存在的实体,拥有自己独立的资源,拥有自己私有的地址空间。在没有进过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。

  • 动态性:程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。

  • 并发性:多个进程可以在单个处理器上并发执行,多个进程间不会互相影响。

并发性和并行性是两个概念,并行指在同一时刻有多条指令在多个处理器上同时执行;

并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

线程

  • 多线程扩展了多进程的概念,使得一个进程可以同时并发处理多个任务。线程也被称为轻量级进程,线程是进程的执行单元。当进程被初始化后,主线程就被创建了。

  • 线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不再拥有系统资源,它与父进程的其他线程共享改进程所拥有的全部资源。一个线程可以撤销和创建另一个线程,同一个进程中的线程之间可以并发执行。

多线程的优点

  • 进程间不能共享内存,但线程之间共享内存非常容易。

  • 系统创建进程需要为该进程重新分配系统资源,但创建线程代价小的多,因此使用多线程来实现多任务并发比多进程的效率高。

创建线程

使用实例方法,返回一个NSThread对象,必须调用start方法启动线程:

1
2
3
4
NSThread *thread = [[NSThread alloc]initWithTarget:self 
selector:@selector(run)
object:nil];
[thread start];

直接创建并启动线程:

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

线程状态

  • 当程序创建线程后,该线程处于新建状态,仅仅由系统为其分配了内存,并初始化其成员变量的值;当线程对象调用了start方法后,该线程处于就绪状态,系统会为其创建方法调用栈和程序计数器,处于这种状态中的线程并没有开始运行,它只是表示该线程可以运行了,至于何时运行取决于系统的调度。

  • 如果希望调用子线程的start方法后子线程立即开始执行,程序可以使用[NSThread sleepForTimeInterval:0.001];让当前运行的线程(主线程)睡眠1毫秒。

终止线程

线程会以一下3中方式之一结束:

  • 线程执行体方法执行完成,线程正常结束
  • 线程执行过程中出现了错误
  • 直接调用NSThread类的exit方法来终止当前正在执行的线程

当主线程结束时,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位。

为了测试某个线程是否正在运行,可以调用线程对象的 isExecuting、isFinished 方法;如果希望在UI中终止子线程,NSThread 并没有提供方法来终止某个线程,可以通过先执行 [thread cancel] 改变线程状态,然后在此线程执行体方法中使用 [NSThread currentThread].isCancelled 判断 thread 对象的状态,如果 isCancelled 为 YES,就使用 [NSThread exit] 终止当前子线程。

线程睡眠

如果需要将当前正在执行的线程暂停一段时间,并进入阻塞状态,可以通过以下方法实现:

1
2
3
4
// 让当前正在执行的线程暂停t秒,并进入阻塞状态
[NSThread sleepForTimeInterval:t];
// 让当前执行的线程暂停到aDate代表的时间,并进入阻塞状态
[NSThread sleepUntilDate:aDate];

回调主线程刷新UI一般使用以下方法:

1
2
3
4
[self performSelectorOnMainThread:@selector(updateUI:)
withObject:image waitUntilDone:YES];
或者
dispatch_async(dispatch_get_main_queue(), ^{...});

改变线程的优先级

每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会。NSThread提供如下方法设置获取线程的优先级:

1
2
3
4
5
6
7
8
// 该类方法获取当前正在执行的线程的优先级
[NSThread threadPriority];
// 该实例方法获取调用该方法的线程对象的优先级
[thread threadPriority];
// 该类方法用于设置当前正在执行的线程的优先级,参数可以是double类型的0.0~1.0的浮点数
[NSThread setThreadPriority:priority];
// 该实例方法用于设置该方法的线程对象的优先级
[thread setThreadPriority:priority];