要了解多线程首先要知道什么是进程,什么是进程?算法
#pragma mark - 串行(一个接一个,排队跑步,保持队形)队列 - (void)gcdDemo1 { // 将操做放在队列中// 使用串行队列,的异步任务很是很是很是有用!新建子线程是有开销的,不能无休止新建线程 // 建立一个串行队列 dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); // 非ARC开发时,千万别忘记release // dispatch_release(q);for (int i = 0; i < 10; ++i) { // 异步任务,并发执行,可是若是在穿行队列中,仍然会依次顺序执行 dispatch_async(q, ^{ // [NSThread currentThread] 能够在开发中,跟踪当前线程 // num = 1,表示主线程 // num = 2,表示第2个子线程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } }
上面的代码是建立一个串行队列,并添加10个任务到队列中,运行这个方法时,你会看到控制台输出的顺序是从1到10的,证实这10个任务是一个执行完在执行另外一个,而且是按照添加顺序来的网络
再来看一下并发队列里面添加10个任务会怎样多线程
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 同步任务顺序执行 dispatch_async(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
从控制台的打印信息来看,你会看到打印是无序的,因此能够验证,并行队列不是(((按照顺序 && 执行完一个才执行一个的)))并发
可是前四个打印中确定有(0,1,2,3){若是开启了四个线程的话}中的一个,由于并行队列里面前四个是0,1,2,3,因此前四个打印中,确定会有其中一个异步
同时咱们注意到上面向队列里面添加任务时候都是用的dispatch_async异步执行,那若是用dispatch_sync同步执行会是什么结果呢?async
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 同步任务顺序执行 dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
根据控制台的输出咱们能够看到,输出是按顺序来的,而且打印出来的Tread信息都是主线程,证实上面任务的执行都是在主线程上完成的函数
(由于因此的任务都按顺序从队列里面出来,而且处理的线程就一个,因此会挨个执行)性能
由于这个代码所在的线程就是主线程,因此sync就在本线程中执行(不开辟新线程)spa
一样的,咱们来看一下串行队列里的同步任务执行结果:线程
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); for (int i = 0; i < 10; ++i) { // 同步任务顺序执行 dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
你会看到跟上面同样的结果
下面咱们再来看一下并行队列时的一些问题
- (void)gcdDemo2 { dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 异步任务(第一批任务) dispatch_async(q, ^{ // [NSThread currentThread] 能够在开发中,跟踪当前线程 // num = 1,表示主线程 // num = 2,表示第2个子线程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } for (int i = 0; i < 10; ++i) { // 同步任务顺序执行(第二批任务) dispatch_sync(q, ^{ NSLog(@"%@ %dkkkkkk", [NSThread currentThread], i); }); } }
你会看到第一批任务里面的打印会无序的打印出来,第二批任务会按照顺序打印(带有kkkk的),可是第一批跟第二批任务是穿插进行的有时候打印第一批里面的,有时候打印第二批里面的
而且已还回发现打印第一批任务的有好几个线程(线程2,线程3...),,打印第二批任务的只有主线程
因此从这里能够看出,CPU执行任务的时候是给各个线程轮流使用的
可是你再看看下面的代码
#pragma mark - 并行(并排跑,相似于赛跑) - (void)gcdDemo2 { // 并行队列容易出错!并行队列不能控制新建线程的数量! dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); //第一轮任务 for (int i = 0; i < 10; ++i) { // 同步任务顺序执行 dispatch_sync(q, ^{ NSLog(@"%@ %dkkkk", [NSThread currentThread], i); }); } // 第二轮任务 for (int i = 0; i < 10; ++i) { // 异步任务 dispatch_async(q, ^{ // [NSThread currentThread] 能够在开发中,跟踪当前线程 // num = 1,表示主线程 // num = 2,表示第2个子线程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } }
你会发现第一轮任务里面的按照1,2,3,4,5,6,7.....这样打印出来,而且第一轮任务执行完毕才会执行第二轮任务
并且第二轮任务会无顺序的打印出数字,这又为何呢,就跟上一份代码两批任务的添加顺序呢换了一下,结果差异怎么那么大呢?
由于第一轮任务使用的同步方法,什么是同步方法呢?同步就是不会建立新的线程,当执行到那个同步任务的时候,当前的线程是谁,谁就去执行这些任务
而上面的代码中,执行到同步任务的是主线程(num = 1),因此主线程就会按照顺序去执行打印任务
而第二批任务是异步方法,异步方法会建立新的线程去执行任务,因此们的ThreadNum=2,3,4等等等,而且执行顺序是没法预估的(无序打印)
到这里你可能还会有一个疑问就是为何两批任务不会像上一份代码那样,穿插着执行,而是先执行第一批在执行第二批呢?
这事由于第一批里面用了同步而且执行到第一批的是主线程,下面咱们来详细解释一下
主线程是伴随着程序运行而运行的,只要程序不挂掉,主线程就会一直运行,线程处理任务的时候是执行完一个,在执行第二个,一个线程不可能同时执行多个任务
,并且其余线程都是由主线程去建立的,主线程就相似于一个超牛逼的人,而且他会造人技术,他须要别人帮忙的时候就会造一我的出来去帮他干活,
可是这个超牛逼人每次只能干一件事,干完一件事才能干另外一件,,,,你仔细看上面的代码就会发现,第一批的10个任务是先添加到主线程里面的,第二批的任务是后来出现的而且须要新的人去执行,,,,,,单此时主线程(超牛逼的那我的)已经有10个任务了,他必须先把这10个任务干完才能去开辟一个新的线程(造人帮他干活),因此
他会先把这10个任务完成之后,他才会开辟新的线程去帮他执行另外的任务,,,,,,,,,从这里就能够很轻松的理解为何先添加同步任务和先添加异步任务结果不一样了
(先添加异步任务...上上份代码... 就是先把造人的事情分给了主线程,然后才给他分配的打印的任务),因此他造出来的人会和本身同时执行任务
由于每次建立队列都很麻烦,因此苹果给咱们提供了两个能够快速获取的队列---主队列和全局队列
下面是获取代码
// 每个应用程序都只有一个主线程 // 为何须要在主线程上工做呢? // 在iOS开发中,全部UI的更新工做,都必须在主线程上执行! dispatch_queue_t q = dispatch_get_main_queue(); // 全局队列与并行队列的区别 // 1> 不须要建立,直接GET就能用 // 2> 两个队列的执行效果相同 // 3> 全局队列没有名称,调试时,没法确认准确队列 // 记住:在开发中永远用DISPATCH_QUEUE_PRIORITY_DEFAULT // 多线程的优先级反转!低优先级的线程阻塞了高优先级的线程! dispatch_queue_t q =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
上面两行代码分别是获取主队列和全局队列的方法
添加到主队列里的任务会放在主线程里执行,这里须要注意的是,若是你使用了主队列,必定不要使用sync同步方法,而要是用异步方法
这个事为何呢?1.主队列是一个串行队列,会依次执行任务,执行完一个执行另外一个
2.sync同步方法不会建立新的线程,会在执行到那句代码所在的线程执行
由于主线程会一直执行到程序关闭,因此主线程里面的任务是执行不完的,若是在主队列里添加同步任务,由于主线程里的任务是执行不玩的,因此你添加的那个任务永远不会被执行(这里请注意,主队列和主线程不是一回事,线程是处理任务的, 队列是给线程送任务的)
在使用主队列时应该使用sync异步方法去执行任务,这样不用等主线程执行完毕就能够执行到任务,须要注意的是在主队列里不会建立新的线程,即便使用async一步方法也不会建立新的线程
可能上面的主队列比较难理解,下面来看个好理解的
#pragma mark 同步任务的阻塞 - (void)gcdSyncDemo { dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); // 任务1 dispatch_sync(q, ^{ NSLog(@"sync %@", [NSThread currentThread]); // 任务2,同步里面包含同步,会形成阻塞 dispatch_sync(q, ^{ // 永远也不会执行到 NSLog(@"async %@", [NSThread currentThread]); }); }); }
上面是一个任务的嵌套,由于添加顺序是任务1先添加,任务2后添加,而且是同步队列,多以任务2会等任务1完成之后再执行,可是此时任务2在任务1的里面,若是任务2没有执行完,任务1是不可能执行完的,此时就是任务1等任务2完成 任务2,等任务1完成,两个任务都等待对方完成本身才能完成,这样两个任务都不会完成
而主队列里面添加同步任务就相似上面的状况,主队列里面一个巨大的任务等待小的同步任务完成,二小的同步任务等待包含他的巨打的任务完成,形成相互等待,结果就是谁完成不了