浅谈IOS的多线程

    在同一时刻,一个CPU只能处理1条线程,但CPU可以在多条线程之间快速的切换,只要切换的足够快,就造成了多线程一同执行的假象。

    多线程是通过提高资源使用率来提高系统总体的效率。

    主线程:处理UI,所有更新UI的操作都必须在主线程上执行。不要把耗时操作放在主线程,会卡界面。

    运用多线程的目的是:将耗时的操作放在后台执行!

一.线程的生命周期:

    新建- 就绪- 运行- 阻塞- 死亡

1.新建:实例化线程对象

2.就绪:详线程对象发送start消息,线程对象被加入可调度线程池等待CPU调度。

3.运行:CPU负责调度可调度线程池中线程的执行。线程执行完成之前,状态可能会在就绪和运行之间来回切换。就绪和运行之间的状态变化由CPU负责,程序员不能干预。

4.阻塞:当满足某个预定条件时,可以使用休眠或锁,阻塞线程执行。sleepForInterval(休眠指定时长),sleepUntilData(休眠到指定日期),@synchronized(self)(互斥锁)

5.死亡:正常死亡,线程执行完毕。非正常死亡,当满足某个条件后,在线程内部中止执行/在主线程中止线程对象。

二.多线程的几种方式:

    PThread:

一套C语言的通用的多线程API,适用于Unix/Linux/Windows等系统,跨平台,可移植。使用难度比较大,内存自己管理。

 

    NSThread:

OC语言的,使用更加面向对象,简单易用,可直接操作线程对象。不太常用,自己管理内存。

三种创建方式

    init方式,

   detachNewThreadSelector创建好之后自动启动,

   performSelectorInBackground创建好之后也是直接启动

类方法:

   [NSThread currentThread];                //当前线程

   [NSThread sleepForTimeInterval:2];         //休眠多久

   [NSThread sleepUntilDate:[NSDate date]];   //休眠到指定时间

   [NSThread exit];                          //退出线程

   [NSThread isMainThread];             //判断当前线程是否为主线程

   [NSThread isMultiThreaded];           //判断当前线程是否是多线程

   属性:

   thread.isExecuting; //线程是否在执行

   thread.isCancelled; //线程是否被取消

   thread.isFinished; //线程是否完成

thread.isMainThread; //是否是主线程

   thread.threadPriority; //线程的优先级,取值范围0.01.0,默认优先级0.51.0表示最高优先级,优先级高,CPU调度的频率高

 

    GCD:

C语言的,GCD会自动利用更多的CPU内核,GCD自动管理线程的生命周期,例如创建线程,调度任务,销毁线程等,只要告诉GCD想要如何执行什么任务,不需要编写任何线程管理代码,易用。

队列创建方法:

   dispatch_queue_create(“队列标示”,“DISPATCH_QUEUE_SERIAL

串行或DISPATCH_QUEUE_CONCURRENT并行”)

   dispatch_get_main_queue()  // 回到主线程进行UI操作

   dispatch_get_global_queue(0, 0)  //全局并发队列,第一个参数是优先级。

任务执行方式:

同步:dispatch_sync

异步:dispatch_async

应用:

1.串行同步:在主线程上,不开启新线程。

2.串行异步:开启一条新线程,顺序执行。

3.并发同步:主线程上,不开启新线程。

4.并发异步:开启多条线程,无顺序执行。

5.主队列同步:发生死锁,程序崩溃。

       原因:如果在主线程中运用主队列同步,也就是把任务放到了主线程的队列中。而同步对于任务是立刻执行的,那么当把第一个任务放进主队列时,它就会立马执行。可是主线程现在正在处理syncMain方法,任务需要等syncMain执行完才能执行。syncMain执行到第一个任务的时候,又要等第一个任务执行完才能往下执行第二个和第三个任务。这样syncMain方法和第一个任务就开始了互相等待,形成了死锁。

6. 主线程异步:主线程上顺序执行

其他用法:

GCD栅栏:dispatch_barrier_async,可以分组执行。

     GCD延时执行:dispatch_after。

GCD一次执行:dispatch_once能保证某段代码在程序运行过程中只被执行1次。常用于单例。

    GCD快速迭代:dispatch_apply。常用于遍历

    GCD队列组:异步,并发。dispatch_group_create创建一个队列组,dispatch_group_notify监听任务是否完成。

 

NSOPeration:

基于底层的GCD,比GCD多了一些更简单使用的功能,使用更加面向对象,OC语言的,自动管理内存。经常使用。

     NSOperation实现多线程步骤:创建任务:先将需要执行的操作封装到NSOperation对象中。创建队列:创建NSOperationQueue。将任务加入到队列中:将NSOperation对象添加到NSOperationQueue中。

创建方式:

    1.NSInvocationOperation对象并关联方法,之后start。(在主线程下执行,没有开启新线程。如果加入队列,就会开启新的线程,在子线程下执行)

    2.NSBlockOperation创建对象,创建block中的任务是在主线程执行(加入队列,会开启新的线程,在自线程下执行)。

   addExecutionBlock加入的任务是在子线程中执行。

   3.继承自NSOperation的子类。然后重写它的main方法,

队列NSOperationQueue

主队列、其他队列(并发和串行)。

最大并发数。maxConcurrentOperationCount-1,代表多线程)

NSOperation的其他操作:

1. - (void)cancelAllOperations    //取消队列NSOperationQueue的所有操作。

     2. - (void)cancel                //取消NSOperation的某个操作,NSOperation对象方法  

     3.[queue setSuspended:YES];      //使队列暂停或继续

 4. - (BOOL)isSuspended          //判断队列是否暂停

     5.  [operation2 addDependency:operation1];   //操作依赖,2依赖1

三.线程安全问题:

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

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

    

    nonatomic 非原子属性,同一时间可以有很多线程读和写。非线程安全,不过效率更高。

atomic 原子属性(线程安全),保证同一时间只有一个线程能够写入(但是同一个时间多个线程都可以取值),atomic 本身就有一把锁(自旋锁),线程安全,需要消耗大量的资源。

 

四.Block的一些问题:

1.IOS项目中使用的好处和缺点?

    好处:

    使用线程可以把占据时间长的程序中的任务放到后台去处理

    用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度

    程序的运行效率可能提高

    在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。

缺点:

如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。

    更多的线程需要更多的内存空间。

    线程的中止需要考虑其对程序运行的影响。

2.一次执行是怎么做到的?如果让你来实现dispatch_once,你会怎么做?

    1.线程A执行Block时,任何其它线程都需要等待。

    2.线程A执行完Block应该立即标记任务完成状态,然后遍历信号量链来唤醒所有等待线程。

    3.线程A遍历信号量链来signal时,任何其他新进入函数的线程都应该直接返回而无需等待。

    4.线程A遍历信号量链来signal时,若有其它等待线程B仍在更新或试图更新信号量链,应该保证此线程B能正确完成其任务:a.直接返回b.等待在信号量上并很快又被唤醒。

    5.线程B构造信号量时,应该考虑线程A随时可能改变状态(“等待”、“完成”、“遍历信号量链”)。

    6.线程B构造信号量时,应该考虑到另一个线程C也可能正在更新或试图更新信号量链,应该保证B、C都能正常完成其任务:a.增加链节并等待在信号量上b.发现线程A已经标记“完成”然后直接销毁信号量并退出函数。

3. NSOperation与GCD的区别?

    GCD是将任务(block)添加到队列(串行、并行、全局、主队列),并且以同步/异步的方式执行任务的函数。GCD提供了一些NSOperation不具备的功能:一次性执行,延迟执行,调度组,GCD 是严格的队列,先进先出FIFO;     

    NSOperation是将操作(异步的任务)添加到队列(并发队列),就会执行指定的函数。NSOperation提供的方便操作:1.最大并发数。2.队列的暂停和继续。3.取消所有的操作。4.指定操作之间的依赖关系依赖关系,可以让异步任务同步执行。5.将KVO用于NSOperation中,监听一个operation是否完成。6.能够设置NSOperation的优先级,能够使同一个并行队列中的任务区分先后地执行。7.对NSOperation进行继承,在这之上添加成员变量与成员方法,提高整个代码的复用度。

猜你喜欢

转载自blog.csdn.net/pdd_1128/article/details/80310302