多线程初认识
一、多线程的基本概念
二、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函数
将来的自己,会感谢现在不放弃的自己!