IOS中的多线程
进程和线程
一个运行中的程序我们称之为进程,进程负责内存的分配。代码是由线程来执行,一个进程可以有多个线程(执行路径),但至少有一个线程(主线程),主线程一般都是程序的入口---main函数。
IOS中的线程
IOS的每条线程在栈区能使用的资源是有限的,主线程是1M,子线程是512K。
IOS中一条执行中的线程不允许程序员手动终止,只能等待该线程中的所有代码跑完,并由系统自动销毁。但程序员可以控制线程的睡眠或暂停。
IOS中实现线程的三种方式
NSThread (不推荐)
使用NSThread建立一个线程十分方便,可用NSThread管理多个线程十分麻烦。
NSOperation/NSOperationQueue (看情况,优先使用GCD)
是使用GCD实现的一套基于Objective-c的API,因此是用面向对象的思维方式实现,提供了一些GCD不容易实现的一些特征。如,限制最大并发数量,操作之间的依赖关系。
GCD (推荐,使用起来比NSOperation方便)
它是一套基于C语言的API,使用Block来定义执行的任务,简单快速。只支持IOS4.0后的版本。
使用GCD方式实现多线程
GCD中有两个概念:任务和队列,主要思想就是将任务放在队列中,队列会根据队列的类型和任务的类型自动分配调用任务执行所在的线程以及具体的执行时间。
任务:执行的任务,使用block方式实现。
队列:用来存放若干个任务,队列是先进先出的,后添加进的线程会被排在对尾。
任务的种类:异步和同步
异步任务就像大家一起赛跑,异步任务的后面的任务会被执行,不会被堵塞住。
同步任务就是大家排队,如果同步任务不执行完,后面的任务不会执行。
串行队列
串行队列中的所有任务都是依次执行的,前面的任务没有执行完后面的不会被执行。像是一根香,是按顺序烧的。
示例1:串行队列中第一个任务的类型是异步的,第二个也是异步的。那么这两个线程都会被执行
dispatch_queue_create的第一个参数是队列的名字,第二个参数是队列的类型,它接受一个枚举值
定义一个队列的两种方式:
串行队列对应的枚举:DISPATCH_QUEUE_SERIAL
并行队列对应的枚举:DISPATCH_QUEUE_CONCURRENT
定义一个操作的两种方式:
dispatch_async方法定义一个异步操作
dispatch_sync方法定义一个同步操作
串行队列中不会给同步操作分配新线程(基本没用)
NSLog(@"%@",[NSThread currentThread]); [super viewDidLoad]; //1.定义一个串行队列 dispatch_queue_t q = dispatch_queue_create("fristThread", DISPATCH_QUEUE_SERIAL); //2.加入一个同步操作 dispatch_sync(q, ^{ NSLog(@"%@",[NSThread currentThread]); }); /*输出结果: <NSThread: 0x8e8b070>{name = (null), num = 1} <NSThread: 0x8e8b070>{name = (null), num = 1} */
串行队列会给异步任务分配一个新线程(非常有用)。
NSLog(@"%@",[NSThread currentThread]); [super viewDidLoad]; //1.定义一个串行队列 dispatch_queue_t q = dispatch_queue_create("fristThread", DISPATCH_QUEUE_SERIAL); //2.加入一个异步操作 dispatch_async(q, ^{ NSLog(@"%@",[NSThread currentThread]); }); /*输出结果: <NSThread: 0x8e71e90>{name = (null), num = 1} <NSThread: 0x8d78df0>{name = (null), num = 2} */
并行队列
并行队列中的任务都是并发执行的,没有先后顺序。
并行队列中的所有异步任务没有固定的执行顺序,都是并发执行,系统会为它们开辟多条线程。并行队列程序员无法指定线程、每个任务的执行顺序。
NSLog(@"%@",[NSThread currentThread]); [super viewDidLoad]; //1.定义一个并行队列 dispatch_queue_t q = dispatch_queue_create("fristThread", DISPATCH_QUEUE_CONCURRENT); //2.加入一个异步操作 for (int i = 0; i < 10;i++) { dispatch_async(q, ^{ NSLog(@"%@ %d",[NSThread currentThread],i); }); } /*输出结果: 2014-04-25 12:41:31.524 多线程[748:60b] <NSThread: 0x8e52170>{name = (null), num = 1} 2014-04-25 12:41:31.526 多线程[748:1303] <NSThread: 0x8c536d0>{name = (null), num = 2} 0 2014-04-25 12:41:31.526 多线程[748:3503] <NSThread: 0x8e9e100>{name = (null), num = 4} 2 2014-04-25 12:41:31.526 多线程[748:3603] <NSThread: 0x8c56190>{name = (null), num = 5} 3 2014-04-25 12:41:31.526 多线程[748:3403] <NSThread: 0x8c56090>{name = (null), num = 3} 1 2014-04-25 12:41:31.528 多线程[748:1303] <NSThread: 0x8c536d0>{name = (null), num = 2} 4 2014-04-25 12:41:31.529 多线程[748:3503] <NSThread: 0x8e9e100>{name = (null), num = 4} 5 2014-04-25 12:41:31.529 多线程[748:3603] <NSThread: 0x8c56190>{name = (null), num = 5} 6 2014-04-25 12:41:31.529 多线程[748:3403] <NSThread: 0x8c56090>{name = (null), num = 3} 7 2014-04-25 12:41:31.530 多线程[748:1303] <NSThread: 0x8c536d0>{name = (null), num = 2} 8 2014-04-25 12:41:31.530 多线程[748:3503] <NSThread: 0x8e9e100>{name = (null), num = 4} 9 */
并行队列中的所有同步任务都是按顺序执行,任务由主线程顺序执行。
NSLog(@"%@",[NSThread currentThread]); [super viewDidLoad]; //1.定义一个串行队列 dispatch_queue_t q = dispatch_queue_create("fristThread", DISPATCH_QUEUE_CONCURRENT); //2.加入一个同步操作 for (int i = 0; i < 10;i++) { dispatch_sync(q, ^{ NSLog(@"%@ %d",[NSThread currentThread],i); }); } /*输出结果: 2014-04-25 12:46:33.939 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 2014-04-25 12:46:33.941 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 0 2014-04-25 12:46:33.941 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 1 2014-04-25 12:46:33.941 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 2 2014-04-25 12:46:33.942 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 3 2014-04-25 12:46:33.942 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 4 2014-04-25 12:46:33.942 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 5 2014-04-25 12:46:33.943 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 6 2014-04-25 12:46:33.943 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 7 2014-04-25 12:46:33.944 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 8 2014-04-25 12:46:33.944 多线程[779:60b] <NSThread: 0x8d293a0>{name = (null), num = 1} 9 */
名字的作用:
全局队列
全局队列其实就是并行队列,唯一不同的是全局队列没有队列名,在整个项目中共享这一个队列。
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//后面的0是固定写法。
主队列
主队列中不应该使用同步操作,因为主队列中默认已经有一个同步操作了,它就是main函数,如果加入同步操作会被main函数堵塞住。
为什么更新UI的操作只能放到主队列?主队列中只能放异步操作,异步操作就会有安全问题,是不是一个队列对应同一个CPU啊?