疯狂iOS讲义下:
第七章:多线程
本章要点:
多线程知识和多线程优势
使用NSThread创建和启动线程
线程的状态
终止子线程
线程睡眠
改变线程优先级
iOS应用开发中线程安全问题
使用@synchronized实现同步
释放同步监视器的锁定
同步锁(NSLock)
使用NSCondition控制线程通信
实例:生产者-消费者
使用GCD实现多线程
异步提交任务
使用GCD同步提交任务
使用GCD提交多次执行的任务
使用GCD提交只执行一次的任务
控制iOS应用在后台运行
控制iOS应用进入后台运行
控制iOS应用进入后台时保存状态
请求更多地后台时间
使用NSOperation与NSoperationQueue实现多线程
通过NSOperation子类实现多线程
单线程程序如同只雇用一个服务员的单停,他必须做完一件事情后才能做下一件事情;多线程程序如同雇佣多个服务员的餐厅,他们可以同时进行着多件事情。
每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。
进程是系统进行资源分配和调度的一个独立单位。
进程的3个特征:
独立性;
动态性:进程和程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。进程具有自己的生命周期和各种不同的状态。
并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。
注意:并发性和并行性是两个概念,并行是指在同一时刻,有多条指令在多个处理器上同时执行;并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
线程也被称作轻量级进程。线程是进程的执行单元。就像进程在操作系统中的低位一样,线程在程序中是独立的、并发的执行流。当进程被初始化后,主线程就被创建了。对于绝大多数的应用程序来说,通常仅要求有一个主线程,但也可以在该进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程也是相互独立的。
线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不再拥有系统资源,它与父进程的其他线程共享该进程所有的全部资源。因为多个线程共享父进程里的全部资源,因此编程更加方便;但必须确保线程不会妨碍统一进程里的其他线程。
线程之间相互协同来完成进程所要完成的任务。
线程是独立运行的,它并不知道进程中是否还有其他线程存在。线程的执行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行。
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
操作系统不会将多个线程看做多个独立的应用,对多线程实现调度和资源分配是由进程本身负责完成。
简而言之:一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程。
总结就是:操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。
1.2 多线程的优势
线程比进程具有更高的性能,是由于同一个进程中的线程都有共性——多个线程将共享同一个进程虚拟空间。下车高共享的环境包括:进程代码段、进程的公有数据等。利用这些共享的数据等,线程很容易实现相互之间的通信。
当操作系统创建一个进程时,必须为该进程分配独立的内存空间,并分配大量的相关资源;但创建一个线程则简单得多,一次使用多线程来实现并发比使用多进程实现并发的性能要高得多。
总结多线程编程的优点:
a. 进程间不能共享内存,但线程之间共享内存非常容易。
b. 系统创建进程需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高。
c. iOS提供了多种多线程实现方式,从而简化了iOS的多线程编程。
(主线程又称作UI线程)
iOS大致提供了如下3种多线程编程的技术:
a. 使用NSThread 实现多线程。
b. 使用NSOperation与NSOperationQueue 实现多线程。
c. 使用GCD(Grand Central Dispatch)实现多线程。
这3种多线程编程的技术,抽象度层次是从低到高的,抽象度越高的用法越简单。
理解NSThread才能更好地理解编程的本质与细节。
iOS使用NSThread类代表线程,创建县县城也就是创建NSThread对象。
2.1创建和启动线程
创建NSThread有两种方式:
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)arg;创建并启动新线程。
上面两种方式的本质都是将target对象的selector方法转换为线程执行体,其中selector方法最多可以接受一个参数,而arg就代表传给selector方法的参数。
提示:target对象的selector方法的方法体代表了线程需要完成的任务,因此相当于把target对象的selector方法转换为线程执行体。
第一种方法会返回一个NSThread对象,必须要调用start方法启动线程;
第二种方法不会返回NSThread对象,因袭这种方式会直接创建并启动线程。
2.2 线程的状态
【当线程对象调用了start方法之后,该线程出狱就绪状态,系统会为其创建方法调用栈和程序计数器,处于这种状态中的线程并没有开始运行,它只是表示该线程可以运行了。置于该线程何时开始运行,取决于系统的调度。】
启动线程使用start方法,线程启动之后并不是立即进入运行状态,线程被启动后处于就绪状态,当系统调度线程后,线程才会进入运行状态。
2.3 终止子线程
a. 线程执行体方法执行完成,线程正常结束。
b. 线程执行过程中出现了错误。
c. 直接调用NSThread类的exit方法来中止当前正在执行的线程。
注意:当主线程结束时,其他线程不受任何影响,并不会随之结束,一旦子线程启动起来后,它就拥有和主线程相同的地位,他不会受主线程的影响。
2.4 线程睡眠
NSThread类提供了如下两个控制线程暂停的类方法:
+(void)sleepUntilDate:(NSDate *)aDate;让当前正在执行的线程暂停到aDate代表的时间,并进入阻塞状态。
+(void)sleepForTimeInterval:(NSTimeInterval)ti;让当前正在执行的线程暂停ti秒,并进入阻塞状态。
当前线程调用睡眠方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他 可执行的线程,处于阻塞状态的线程也不会执行,因此常用来暂停线程的执行。
未完。。。。。