一、多线程的基本概念
二、NSThread
资源竞争原理图
多条线程同时访问同一个资源
//4.做耗时操作时,多个线程访问同一个资源
self.ticketCount = 100;
self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadA.name = @"售票员A";
self.threadB.name = @"售票员B";
self.threadC.name = @"售票员C";
//启动线程
[self.threadA start];
[self.threadB start];
[self.threadC start];
//执行方法
- (void)saleTicket{
//锁:必须是全局唯一性的
//1.注意加锁的位置
//2.注意加锁的条件,多线程共享同一块资源
//3.注意加锁是需要付出代价的,需要耗费性能
//4.加锁的条件:线程同步
//如果不加锁的话就会出错
while (1) {
@synchronized (self) {
NSInteger count = self.ticketCount;
if (count > 0) {
//耗时操作
for (NSInteger i = 0; i< 100000; i++) {
}
self.ticketCount = count -1;
NSLog(@"%@卖出去了一张票,还剩下%zd张票", [NSThread currentThread].name,self.ticketCount);
}else{
NSLog(@"票卖完了");
break;
}
}
}
}
三、GCD
四、NSOperation
五、代码实例
1.NSOperation
2.GCD
//1.异步函数+串行队列,开一条线程,队列中的任务是串行执行的
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download3---%@",[NSThread currentThread]);
});
//2.异步函数+并行队列,开多条线程,队列中的任务是并行执行的
dispatch_queue_t queue = dispatch_queue_create("current", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download3---%@",[NSThread currentThread]);
});
//3.异步函数+主队列,所有任务都会在主线程中完成,不会开线程
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download3---%@",[NSThread currentThread]);
});
//4.同步函数+串行队列,不会开线程,任务是串行执行的
dispatch_queue_t queue = dispatch_queue_create("seria", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"downloadload1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"downloadload2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download3---%@",[NSThread currentThread]);
});
//5.同步函数+并行队列,不会开线程,任务是并行执行的
dispatch_queue_t queue = dispatch_queue_create("seria",DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"download01-------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download02-------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download03-------%@",[NSThread currentThread]);
});
//6.//同步函数+主队列= 死锁,如果该线程在子线程中执行,那么所有队列就会在主线程执行
//同步函数,会崩掉
//同步函数:立刻马上执行,如果我没有执行完毕,那么后面的也别想执行
//异步函数:如果我没有执行完毕,那么后面的也可以执行
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"download01------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download02------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download03------%@",[NSThread currentThread]);
});
//7.多线程下载图片
//1.创建子线程下载图片
//DISPATCH_QUEUE_PRIORITY_DEFAULT 0
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//图片地址
NSURL *url = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=da0ec79c738da9774e7a8e2f8561d42f/c83d70cf3bc79f3d6842e09fbaa1cd11738b29f9.jpg"];
//转换成二进制数据
NSData *data = [NSData dataWithContentsOfURL:url];
//转换为图片
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
//更新图片
self.headImageView.image = image;
});
});
//8.延时加载
//延时加载1
// [self performSelector:@selector(task) withObject:nil afterDelay:2];
//延时加载2,用于定时器,repeats是否重复
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(task) userInfo:nil repeats:NO];
//延时加载3,GCD
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
NSLog(@"GCD-----%@",[NSThread currentThread]);
});
//9.栅栏函数
//栅栏函数不能使用全局并发队列
//什么是dispatch_barrier_async函数
//毫无疑问,dispatch_barrier_async函数的作用与barrier的意思相同,在进程管理中起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行,该函数需要同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一起使用
//dispatch_barrier_async函数的作用
//如果是3条线程,并发执行的话,1条线程后面加栅栏函数,必须线程1执行完,才会执行线程2,3
//1.实现高效率的数据库访问和文件访问
//2.避免数据竞争
//获得全局并发队列
// dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT);
//异步函数
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 100; i++) {
NSLog(@"download01--%zd------%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 100; i++) {
NSLog(@"download02----%zd----%@",i,[NSThread currentThread]);
}
});
//栅栏函数
dispatch_barrier_async(queue, ^{
NSLog(@"==========================");
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 100; i++) {
NSLog(@"download03--%zd------%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 100; i++) {
NSLog(@"download04----%zd----%@",i,[NSThread currentThread]);
}
});
//10.GCD的快速迭代
//1.拿到文件的路径
NSString *fromPath = @"/Users/xingzai/Desktop/Tools";
//2.获取文件的路径
NSString *toPath = @"/Users/xingzai/Desktop/Tool";
//3.得到目录下所有文件
NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:fromPath];
//4.count
NSInteger count = subPaths.count;
//5.执行
dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
//拼接全路径,文件的路径
NSString *fullPath = [fromPath stringByAppendingPathComponent:subPaths[index]];
//拼接全路径,文件剪切到的路径
NSString *toFullPath = [toPath stringByAppendingPathComponent:subPaths[index]];
//参数一:文件的路径,参数二:文件剪切的位置
[[NSFileManager defaultManager] moveItemAtPath:fullPath toPath:toFullPath error:nil];
});
//11.创建组队列
//1.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//2.创建队列祖
dispatch_group_t group = dispatch_group_create();
//3.异步函数
/**1.封装对象
2.把任务添加到队列中
3.会监听执行情况,通知group
*/
dispatch_group_async(group, queue, ^{
NSLog(@"1-------%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2-------%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"3------%@",[NSThread currentThread]);
});
//拦截通知,当队列组所有的任务都执行完以后需要执行下面的方法
dispatch_group_notify(group, queue, ^{
NSLog(@"线程全部执行完了");
});
//12.合成对象
/**下载图片1,开子线程
下载图片2,开子线程
合成图片,并开子线程
*/
//1.获取群组
dispatch_group_t group = dispatch_group_create();
//2.获取并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//3.下载图片,开启子线程
dispatch_group_async(group, queue, ^{
NSLog(@"打印当前线程------%@",[NSThread currentThread]);
//3.1图片地址
NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
//3.2下载二进制数据
NSData *data = [NSData dataWithContentsOfURL:url];
//3.3转换图片
self.imageOne = [UIImage imageWithData:data];
});
//下载图片2
dispatch_group_async(group, queue, ^{
NSLog(@"-------%@",[NSThread currentThread]);
//1.图片地址
NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
//2.下载二进制数据
NSData *data = [NSData dataWithContentsOfURL:url];
//3.转换图片
self.imageTwo = [UIImage imageWithData:data];
});
//合成图片
dispatch_group_notify(group, queue, ^{
NSLog(@"-----------%@",[NSThread currentThread]);
//1.创建图形上下文
UIGraphicsBeginImageContext(CGSizeMake(320, 640));
//2.画图形
[self.imageOne drawInRect:CGRectMake(0, 0, 320, 320)];
self.imageOne = nil;
[self.imageTwo drawInRect:CGRectMake(0, 320, 320, 320)];
self.imageTwo = nil;
//3.根据上下文得到一张图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//4.关闭上下文
UIGraphicsEndImageContext();
NSLog(@"%@",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
//更新UI
self.headImageView.image = image;
});
});
//由于dispatch_apply函数与dispatch_sync函数相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步地执行dispatch_apply函数