目前我了解到的多线程编程技术一共有四种,分别是pthread,NSThread,NSOperation,GCD,但在我看来使用最多的还是GCD,今天就先来说说GCD,其他三种请继续关注。。。
首先,GCD是什么。全称是Grand Central Dispatch,是苹果公司开发的技术,一种底层的纯C语言的API,用来处理多核心处理器和其他对称多处理系统。
GCD一共有三种队列类型:
1.The main queue:在程序中向主队列提交的任务会在主线程中执行,通过dispatch_get_main_queue() 来获得,因为是在主线程中完成,所以是串行队列。
2.global queue : 全局队列是并发队列 。调用dispatch_get_global_queue()来获得,dispatch_get_global_queue()一共需要传两个参数,第一个参数是优先级,优先级分为四种(下面有附),分别是高优先级,默认优先级,低优先级,background(这个目前我还不知道是什么优先级),不过参数一般就按照默认优先级走就OK,第二个参数是flag,目前只支持0和NULL。
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
DISPATCH_QUEUE_SERIAL:串行队列,放在此队列中的内容,都是按照FIFO(先进先出)的方式,取出一个来执行一个,也可以理解为多个队列按照排队的方式按照先后顺序一一执行。
DISPATCH_QUEUE_CONCURRENT:并行队列,也是按照FIFO的方式,但是该队列取出一个任务会放到一个线程中,是在不同的线程中执行相应的队列内容,是并发执行的。
注:线程有主线程和子线程之分,用户对UI的操作一定是在主线程上,所以在做加载的时候一定要把线程开到子线程上,才能不影响用户对UI的操作。
//加载图片需要在子线程上,以防阻塞线程造成页面卡死
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSURL * backgroundURL = [NSURLURLWithString:backGroundStr];
NSData * backgroundData = [NSDatadataWithContentsOfURL:backgroundURL];
//更新UI,所以在主线程上
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImageimageWithData:backgroundData];
});
});
这里需要和线程的同步和异步执行还有一定的关系,下面列举了不同的情况。
[self gcdTestMethod:^{
for (int i = 1; i<5; i++)
{
NSString * isMain = [[NSThread currentThread] isMainThread]?@"YES":@"NO";
NSLog(@" 1====%2d %@ Main:%@",i,[NSThread currentThread],isMain);
}
}];
[self gcdTestMethod:^{
for (int i = 0; i<5; i++)
{
NSString * isMain = [[NSThread currentThread] isMainThread]?@"YES":@"NO";
NSLog(@" 2=====%2d %@ Main:%@",i,[NSThread currentThread],isMain);
}
}];
第一种情况:
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
if(!_concurrentQ)
{
_concurrentQ =dispatch_queue_create(NULL,DISPATCH_QUEUE_SERIAL);
}
dispatch_async(_concurrentQ,oneGcdobject);
}
分析:这里的多线程是异步方式,队列是串行队列,所以该队列不会在主线程上,而是在一个新线程上,同时是串行队列,所以排队执行,理论上整个程序是按照哦从上至下的顺序执行,所以第一个for循环会排在前面
执行结果:
2016-01-21 10:42:58.208 多线程_GCD[5366:427771] 1==== 1 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.209 多线程_GCD[5366:427771] 1==== 2 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.209 多线程_GCD[5366:427771] 1==== 3 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.209 多线程_GCD[5366:427771] 1==== 4 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.209 多线程_GCD[5366:427771] 2===== 1 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.210 多线程_GCD[5366:427771] 2===== 2 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.210 多线程_GCD[5366:427771] 2===== 3 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
2016-01-21 10:42:58.210 多线程_GCD[5366:427771] 2===== 4 <NSThread: 0x7fbf39cabb30>{number = 2, name = (null)} Main:NO
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
if(!_concurrentQ)
{
_concurrentQ =dispatch_queue_create(NULL,DISPATCH_QUEUE_CONCURRENT);
}
dispatch_async(_concurrentQ,oneGcdobject);
}
分析:同样是异步线程,但却是同步队列,所以会有两条线程分别执行两个队列,且是同时进行执行结果:
2016-01-21 10:45:42.653 多线程_GCD[5400:429448] 1==== 1 <NSThread: 0x7fb458c1f240>{number = 3, name = (null)} Main:NO
2016-01-21 10:45:42.653 多线程_GCD[5400:429449] 2===== 1 <NSThread: 0x7fb458e08210>{number = 2, name = (null)} Main:NO
2016-01-21 10:45:42.654 多线程_GCD[5400:429448] 1==== 2 <NSThread: 0x7fb458c1f240>{number = 3, name = (null)} Main:NO
2016-01-21 10:45:42.654 多线程_GCD[5400:429449] 2===== 2 <NSThread: 0x7fb458e08210>{number = 2, name = (null)} Main:NO
2016-01-21 10:45:42.654 多线程_GCD[5400:429448] 1==== 3 <NSThread: 0x7fb458c1f240>{number = 3, name = (null)} Main:NO
2016-01-21 10:45:42.654 多线程_GCD[5400:429449] 2===== 3 <NSThread: 0x7fb458e08210>{number = 2, name = (null)} Main:NO
2016-01-21 10:45:42.655 多线程_GCD[5400:429448] 1==== 4 <NSThread: 0x7fb458c1f240>{number = 3, name = (null)} Main:NO
2016-01-21 10:45:42.655 多线程_GCD[5400:429449] 2===== 4 <NSThread: 0x7fb458e08210>{number = 2, name = (null)} Main:NO
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
if(!_concurrentQ)
{
_concurrentQ = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
dispatch_sync(_concurrentQ,oneGcdobject);
}
第四种情况:
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
if(!_concurrentQ)
{
_concurrentQ =dispatch_queue_create(NULL,DISPATCH_QUEUE_CONCURRENT);
}
dispatch_sync(_concurrentQ,oneGcdobject);
}
这两种情况一起说一下,因为是在同步线程上,所以是发生在主线程,在执行代码块时就会发生阻塞,等该代码块执行完毕时才会执行下一个代码块,所以不论当前队列是串行还是并行结果都是一样的
2016-01-21 10:47:00.458 多线程_GCD[5440:430735] 1==== 1 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 1==== 2 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 1==== 3 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 1==== 4 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 2===== 1 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 2===== 2 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.459 多线程_GCD[5440:430735] 2===== 3 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
2016-01-21 10:47:00.460 多线程_GCD[5440:430735] 2===== 4 <NSThread: 0x7fdfa3e03530>{number = 1, name = main} Main:YES
第五种情况:
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
// if(!_concurrentQ)
// {
_concurrentQ = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
NSLog(@"------------");
// }
dispatch_async(_concurrentQ,oneGcdobject);
}
分析:这种情况会创建两个队列同时在两个线程上,且这两个线程互不干扰
2016-01-21 11:08:13.943 多线程_GCD[5620:441506] -----------
2016-01-21 11:08:13.943 多线程_GCD[5620:441506] -----------
2016-01-21 11:08:13.943 多线程_GCD[5620:441637] 1==== 1 <NSThread: 0x7fe9aa70a8d0>{number = 2, name = (null)} Main:NO
2016-01-21 11:08:13.944 多线程_GCD[5620:441640] 2===== 1 <NSThread: 0x7fe9aa45d3a0>{number = 3, name = (null)} Main:NO
2016-01-21 11:08:13.944 多线程_GCD[5620:441637] 1==== 2 <NSThread: 0x7fe9aa70a8d0>{number = 2, name = (null)} Main:NO
2016-01-21 11:08:13.944 多线程_GCD[5620:441640] 2===== 2 <NSThread: 0x7fe9aa45d3a0>{number = 3, name = (null)} Main:NO
2016-01-21 11:08:13.945 多线程_GCD[5620:441637] 1==== 3 <NSThread: 0x7fe9aa70a8d0>{number = 2, name = (null)} Main:NO
2016-01-21 11:08:13.945 多线程_GCD[5620:441640] 2===== 3 <NSThread: 0x7fe9aa45d3a0>{number = 3, name = (null)} Main:NO
2016-01-21 11:08:13.945 多线程_GCD[5620:441637] 1==== 4 <NSThread: 0x7fe9aa70a8d0>{number = 2, name = (null)} Main:NO
2016-01-21 11:08:13.946 多线程_GCD[5620:441640] 2===== 4 <NSThread: 0x7fe9aa45d3a0>{number = 3, name = (null)} Main:NO
第六种情况:
-(void)gcdTestMethod:(gcdBlockObject)oneGcdobject
{
// if(!_concurrentQ)
// {
_concurrentQ = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
NSLog(@"-----------");
// }
dispatch_sync(_concurrentQ,oneGcdobject);
}
分析:由于是同步线程,所以必须在主线程上执行完第一个队列上的任务,才会执行下一个
2016-01-21 11:07:26.484 多线程_GCD[5593:440490] -----------
2016-01-21 11:07:26.484 多线程_GCD[5593:440490] 1==== 1 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 1==== 2 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 1==== 3 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 1==== 4 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] -----------
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 2===== 1 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 2===== 2 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.485 多线程_GCD[5593:440490] 2===== 3 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
2016-01-21 11:07:26.486 多线程_GCD[5593:440490] 2===== 4 <NSThread: 0x7fe2c1608e60>{number = 1, name = main} Main:YES
我也是刚了解,有什么问题再随时补充和修改