iOS多线程有四套多线程方案:
- Pthreads
- NSThread
- GCD
- NSOperation & NSOperationQueue
NSThread
不常用,主要用到[NSThread currentThread]
函数来获取当前线程
GCD (任务和队列)
如果dispatch_group_async里执行的是异步代码dispatch_group_notify会直接触发而不会等待异步任务完成,而dispatch_group_enter、和dispatch_group_leave则不会有这个问题,它们只需要在任务开始前enter结束后leave即可达到线程同步的效果。
|
|
如果block块里面执行的是同步代码,则以用dispatch_group_enter dispatch_group_leave
和dispatch_group_async
实现效果一样
|
|
串行队列
- 同步串行,不会创建新线程,各个任务在主线程中,依次执行
- 异步串行,只创建一次新线程,各个任务依次执行1234567891011121314151617181920212223242526272829// create queuedispatch_queue_t queue = dispatch_queue_create("com.example.gcd.queuename", DISPATCH_QUEUE_SERIAL); //DISPATCH_QUEUE_CONCURRENT// 串行同步不会创建线程dispatch_sync(queue, ^{NSLog(@"serial queue sync task1 --%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"serial queue sync task2 --%@", [NSThread currentThread]);});// 串行异步会创建线程,当前队列中第一次异步会创建线程之后不会在重新创建dispatch_async(queue, ^{NSLog(@"serial queue async task1 --%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"serial queue async task2 --%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"serial queue sync task3 --%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"serial queue async task3 --%@", [NSThread currentThread]);});serial queue sync task1 --<NSThread: 0x600000069480>{number = 1, name = main}serial queue sync task2 --<NSThread: 0x600000069480>{number = 1, name = main}serial queue async task1 --<NSThread: 0x60000066cdc0>{number = 6, name = (null)}serial queue async task2 --<NSThread: 0x60000066cdc0>{number = 6, name = (null)}serial queue sync task3 --<NSThread: 0x600000069480>{number = 1, name = main}serial queue async task3 --<NSThread: 0x60000066cdc0>{number = 6, name = (null)}
并发队列
- 同步并发,不会创建新线程,各个任务在主线程中,依次执行
- 异步并发,每async一次创建一次新线程,任务的执行顺序会根据处理内容和系统状态发生改变
NSOperation & NSOperationQueue
NSOperation是面向对象的。是在GCD基础上封装的,NSOperation和 NSOperationQueue分别对应GCD的任务和队列,可以设置最大并发量,task之间的依赖关系等
一般不直接用NSOperationQueue
,用它的几个子类来操作,否者需要自己管理线程
练习
- 子线程同时执行ABC三个同步任务、全部执行完成再在子线程执行三个同步任务EDF1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495方式一: groupdispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_queue_create("com.emoney.cn", DISPATCH_QUEUE_CONCURRENT);dispatch_group_async(group, queue, ^{NSLog(@"task A");});dispatch_group_async(group, queue, ^{NSLog(@"task B");});dispatch_group_async(group, queue, ^{NSLog(@"task C");});dispatch_group_notify(group, queue, ^{dispatch_sync(queue, ^{NSLog(@"task D, thread:%@", [NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"task E");});dispatch_sync(queue, ^{NSLog(@"task F");});});方式二:dispatch_barrier_asyncThe queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_sync function.官方说明大意:在使用栅栏函数时.使用自定义队列才有意义,如果用的是串行队列或者系统提供的全局并发队列,这个栅栏函数的作用等同于一个同步函数的作用dispatch_queue_t queue = dispatch_queue_create("com.emoney.cn", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{NSLog(@"task A, thread:%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"task B, thread:%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"task C, thread:%@", [NSThread currentThread]);});NSLog(@"ABC");dispatch_barrier_async(queue, ^{NSLog(@"task ABC Done");});dispatch_async(queue, ^{NSLog(@"task D, thread:%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"task E, thread:%@", [NSThread currentThread]);});dispatch_async(queue, ^{NSLog(@"task F, thread:%@", [NSThread currentThread]);});NSLog(@"DEF");方式三:NSOperationQueue dependencyNSOperationQueue *queue = [[NSOperationQueue alloc] init];NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task A, thread:%@", [NSThread currentThread]);}];NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task B, thread:%@", [NSThread currentThread]);}];NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task C, thread:%@", [NSThread currentThread]);}];NSBlockOperation *operationD = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task D, thread:%@", [NSThread currentThread]);}];NSBlockOperation *operationE = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task E, thread:%@", [NSThread currentThread]);}];NSBlockOperation *operationF = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"task F, thread:%@", [NSThread currentThread]);}];[operationD addDependency:operationA];[operationD addDependency:operationB];[operationD addDependency:operationC];[operationE addDependency:operationA];[operationE addDependency:operationB];[operationE addDependency:operationC];[operationF addDependency:operationA];[operationF addDependency:operationB];[operationF addDependency:operationC];[queue addOperation:operationA];[queue addOperation:operationB];[queue addOperation:operationC];[queue addOperation:operationD];[queue addOperation:operationE];[queue addOperation:operationF];
dispatch_semaphore(信号量)的理解及使用
问题描述:
假设现在系统有两个空闲资源可以被利用,但同一时间却有三个线程要进行访问,这种情况下,该如何处理呢?
或者
我们要下载很多图片,并发异步进行,每个下载都会开辟一个新线程,可是我们又担心太多线程肯定cpu吃不消,那么我们这里也可以用信号量控制一下最大开辟线程数。
定义:
1、信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。
其实,这有点类似锁机制了,只不过信号量都是系统帮助我们处理了,我们只需要在执行线程之前,设定一个信号量值,并且在使用时,加上信号量处理方法就行了。
注意,正常的使用顺序是先降低然后再提高,这两个函数通常成对使用。 (具体可参考下面的代码示例)
|
|