一、多线程的基本概念

  • 进程:可以理解成一个运行中的应用程序,是系统进行资源分配和调用的基本单位,是操作系统结构的基础,主要管理资源。
  • 【线程】:进程的基本执行单元,一个进程拥有至少一个线程。
  • 【主线程】:处理UI,所有更新UI的操作都必须在主线程上执行。
  • 【多线程】:在同一时刻,一个CPU只能处理1条线程,但CPU可以在多条线程之间快速的切换,只要切换的速度足够快,就造成了多线程一同执行的假象。

线程就像火车的一节车厢,进程则是火车。车厢(线程)离开火车(进程)是无法跑动的,而火车(进程)至少有一节车厢(主线程)。多线程可以看作多个车厢,他的出现是为了提高效率,另外我们可以利用多线程,将耗时的操作放到后台执行,以防止耗时操作阻塞主线程,导致UI卡顿等现象。


线程的状态与生命周期

下图是线程状态示意图,从图中可以看出线程的生命周期:新建->就绪->运行->阻塞->死亡

ios线程池怎么用 ios线程池的概念_ios线程池怎么用

下面分别阐述线程的生命周期中的每一步:

  • 【新建】:实例化线程对象。
  • 【就绪】:向线程对象发送start消息,线程对象被加入可调度线程池等待CPU调度。
  • 【运行】:CPU负责调度可调度线程池中线程的执行。线程执行完成之前,状态可能会在就绪和运行之间来回切换。就绪和运行之间的状态变化由CPU负责,程序员不能干预。
  • 【阻塞】:当满足某个预定条件时,可以使用休眠或锁,阻塞线程执行。sleepForTimeInterval(休眠指定时长),sleepUntilDate(休眠到指定日期)@synchronized(self),:(互斥锁)。
  • 【死亡】:正常死亡,线程执行完毕。非正常死亡,当满足某个条件后,在线程内部终止执行/在主线程终止线程对象。

补充:

[NSThread exit]:一旦强行终止程序,后续的所有代码都不会被执行。
[thread cancel]:取消线程,并不会直接取消线程,只是给线程对象添加 isCancellled 标记。


多线程的四种解决方案

多线程的四种解决方案:pthread、NSThread、GCD、NSOperation

ios线程池怎么用 ios线程池的概念_主线程_02


线程安全问题

当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。

解决多线程安全问题

  • 方法一:互斥锁
@synchronized(锁对象) {
    // 需要锁定的代码
}

判断的时候锁对象要存在,如果代码中只有一个地方需要加锁,大多数都使用self作为锁对象,这样可以避免单独再创建一个锁对象。

加了互斥锁的代码,当新线程访问时,如果发现其他线程正在执行锁定的代码,新线程就会进入休眠。

  • 方法二:自旋锁

加了自旋锁,当新线程访问代码时,如果发现其他线程正在锁定代码,新线程会采用死循环的方式,一直等待锁定的代码执行完成。相当于不停尝试执行代码,比较消耗性能。

修饰符atomic本身就有一把自旋锁。

atomic与noatomic:

atomic:原子属性(线程安全),保证同一时间只有一个线程能够写入(但是同一个时间多个线程都可以取值)
noatomic:非原子属性,同一时间可以被多个线程读写

atomic:线程安全,但是需要消耗的资源大
noatomic:非线程安全,不过效率很高

  • 方法三:NSLock

创建一个NSLock对象,将需要锁定的代码放在lockUnlock之间

// 初始化数据锁
NSLock *lock =[NSLock alloc]init];
// 数据加锁
[lock lock];
// do something  需要锁定的代码
// 数据解锁
[lock Unlock];