多线程 - 课程分析

来源:互联网 发布:淘宝网售后服务网址 编辑:程序博客网 时间:2024/05/18 00:20

http://blog.csdn.net/fuzheng0301/article/details/46685917


     1.每个进程至少包含一个线程,这个默认创建的线程被成为主线程
     2.单线程程序:程序只包含一个线程(主线程),线程中的代码按顺序执行,缺点:可能会造成主线程阻塞(有些任务耗时比较长)
     3.多线程程序:程序中包含多个线程,线程是独立运行的,提高程序运行效率.
     4.iOS开发中,所有跟UI有关的操作(绘制,刷新)都必须在主线程中完成.
     5.子线程:主线程之外创建的新的线程
     

     △.线程是可以设置优先级的


获取当前线程,判断是否是主线程的方法:

[objc] view plaincopyprint?
  1. NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  


     先创建一个多线程测试环境:

[objc] view plaincopyprint?
  1. -(void)cycle  
  2. {  
  3.     //获取当前线程,判断是否是主线程  
  4.     NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  5.       
  6.     int sum = 0;  
  7.     for (int i=0; i<500; i++) {  
  8.         sum += i;  
  9. //        NSLog(@"%d",i);  
  10.     }  
  11. //    NSLog(@"%d",sum);  
  12. }  

      一 . 使用NSThread实现多线程 : 创建线程后,自动开启,无需手动调用开启

     1.第一个参数:线程中需要执行的方法
     2.第二个参数:执行方法的对象
     3.第三个参数:传值

[objc] view plaincopyprint?
  1. [NSThread detachNewThreadSelector:@selector(cycle) toTarget:self withObject:nil];  


      二 . 使用NSThread实现多线程 : 创建线程后,需要手动开启


[objc] view plaincopyprint?
  1. NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(cycle) object:nil];  
  2. [thread start];  

       三 . 使用NSObject类目方法实现多线程(用的比较多)

[objc] view plaincopyprint?
  1. //隐式创建线程  
  2. [self performSelectorInBackground:@selector(cycle) withObject:nil];  
  3.   
  4. //图片网址  
  5. NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";  
  6. [self performSelectorInBackground:@selector(downloadImage:) withObject:url];  


[objc] view plaincopyprint?
  1. //在子线程中,同步连接下载图片  
  2. -(void)downloadImage:(NSString *)url  
  3. {  
  4.       
  5.     //在子线程中,使用同步方式下载图片.  △备注:在子线程中,不要使用异步连接,会出现问题  
  6.       
  7.     /* 
  8.      △注意事项: 
  9.      1.子线程中没有自动释放池,需要手动添加 
  10.      2.NSThread创建的子线程,默认情况下,任务执行完成后,线程被关闭,销毁 
  11.      3.在子线程中,NSTimer默认情况下,不会执行.如果在子线程中使用NSTimer,必须开启runLoop,方法如下: 
  12.      4.所有线程都有runLoop,主线程默认是开启状态,子线程默认是关闭状态 
  13.      5.子线程开启runLoop后,runLoop不停止,线程无法关闭 
  14.      */  
  15.       
  16.     //获取当前线程的runLoop,并开启  
  17. //    [[NSRunLoop currentRunLoop] run];  
  18.     //获取当前线程的runLoop,并设定运行的时间  
  19. //    [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];  
  20.       
  21.       
  22.     //获取当前线程,判断是否是主线程  
  23.     NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  24.       
  25.       
  26.     //同步下载图片  
  27.     NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];  
  28.     //将data转换成image对象  
  29.     UIImage *image = [UIImage imageWithData:data];  
  30.       
  31.     //△注意:将image在主线程中进行显示.  
  32. //    _imageView.image = image;//这句话位置不对,不能写在这里  
  33.     [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];//第三个参数:等待子线程任务执行完成,再回到主线程执行  
  34.       
  35.     //直接给imageView附图片  
  36. //    [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];  
  37.       
  38. }  
  39. //在主线程中,将image显示在imageView上  
  40. -(void)showImage:(UIImage *)image  
  41. {  
  42.     //获取当前线程,判断是否是主线程  
  43.     NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  44.       
  45.     //参数image是从子线程中返回  
  46.     _imageView.image = image;  
  47.       
  48. }  

        四 . NSOperation 是一个操作类(抽象类),封装了需要执行的任务和数据.   一般不直接使用NSOperation,使用子类:NSInvocationOperation和NSBlockOperation

[objc] view plaincopyprint?
  1. //操作对象封装了需要执行的任务和参数  
  2. NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];  
  3. //开始执行operation对象中封装的任务(方法)  
  4. //start在哪个线程中调用,operation对象中封装的方法就在哪个线程中执行  
  5. [operation start];  

       五 . block方法:

[objc] view plaincopyprint?
  1. NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{  
  2.     NSLog(@"当前线程 %@ ----- 是否是主线程:%d", [NSThread currentThread], [NSThread isMainThread]);  
  3.       
  4.     for (int i = 1; i < 500; i++) {  
  5.           
  6.     }  
  7. }];  
  8.   
  9. [operation start];  

       六 . NSOperationQueue :

      1.NSOperationQueue  操作队列(先进先出),可以管理多个操作对象.
      2.NSOperationQueue  创建的多线程是可以重复使用的,是非脱离线程(线程中的任务完成后,线程进入睡眠状态,未被销毁;NSThread创建的线程是脱离线程)
      3.NSOperationQueue  先加入队列的任务,先执行.(即"先进先出")
      4.NSOperationQueue  控制的线程是并发执行的. 即:队列中的任务按照加入队列的顺序进行分派,但是下一个任务不用等待前一个任务完成再开始.多个任务可以同时执行,互不干扰.  ("并发"相对的是"串行")
      5.什么叫线程同步?  线程A执行结束后才能执行线程B
      6.NSOperationQueue如何实现线程同步?  把最大并发数设置为1,即:每次只允许一个线程执行任务
      7.队列下载

[objc] view plaincopyprint?
  1. NSOperationQueue * queue = [[NSOperationQueue alloc]init];  
  2.   
  3. //设置最大并发数  
  4. queue.maxConcurrentOperationCount = 1;  
  5.   
  6. //添加10个任务  
  7. for (int i=0; i<10; i++) {  
  8.     NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];  
  9.     //操作对象添加到队列里  
  10.     [queue addOperation:operation];  
  11. }  

      七 . 使用GCD的队列实现串行(任务1执行后,任务2再执行) : 

     1.GCD队列类型:主队列,全局队列,自定义队列
     2.GCD队列功能:串行,并发
     3.能够实现串行的有两种队列:主队列和自定义串行队列
     4.能够实现并发的有两种队列:全局队列和自定义并发队列


[objc] view plaincopyprint?
  1. //串行队列 第一种实现:使用主队列  
  2.     /* 
  3.     dispatch_queue_t queue = dispatch_get_main_queue(); 
  4.      
  5.     //向队列异步添加任务 
  6.     dispatch_async(queue, ^{ 
  7.         NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  8.     }); 
  9.     dispatch_async(queue, ^{ 
  10.         NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  11.     }); 
  12.     dispatch_async(queue, ^{ 
  13.         NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  14.     }); 
  15.     dispatch_async(queue, ^{ 
  16.         NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  17.     }); 
  18.     dispatch_async(queue, ^{ 
  19.         NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  20.     }); 
  21.     */  
  22.        
  23.     //串行队列 第二种实现:使用自定义串行队列  
  24.     dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_SERIAL);  
  25.       
  26.     dispatch_async(queue, ^{  
  27.         NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  28.     });  
  29.     dispatch_async(queue, ^{  
  30.         NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  31.     });  
  32.     dispatch_async(queue, ^{  
  33.         NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  34.     });  
  35.     dispatch_async(queue, ^{  
  36.         NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  37.     });  
  38.     dispatch_async(queue, ^{  
  39.         NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  40.     });  
  41.       
  42.     //释放(注意:MRC下需要释放)  
  43. //    dispatch_release(queue);  

        八 . GCD并发:任务A,B,C....按照进入队列顺序开始分派执行

[objc] view plaincopyprint?
  1. //并发队列 第一种实现:全局队列  
  2. /* 
  3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  4. dispatch_async(queue, ^{ 
  5.     NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  6. }); 
  7. dispatch_async(queue, ^{ 
  8.     NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  9. }); 
  10. dispatch_async(queue, ^{ 
  11.     NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  12. }); 
  13. dispatch_async(queue, ^{ 
  14.     NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  15. }); 
  16. dispatch_async(queue, ^{ 
  17.     NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]); 
  18. }); 
  19. */  
  20.   
  21. //并发队列 第二种实现:使用自定义并发队列  
  22.   
  23. dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_CONCURRENT);  
  24.   
  25. dispatch_async(queue, ^{  
  26.     NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  27. });  
  28. dispatch_async(queue, ^{  
  29.     NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  30. });  
  31. dispatch_async(queue, ^{  
  32.     NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  33. });  
  34. dispatch_async(queue, ^{  
  35.     NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  36. });  
  37. dispatch_async(queue, ^{  
  38.     NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);  
  39. });  

         九 . GCD

[objc] view plaincopyprint?
  1. //在子线程中建立同步连接下载图片(把任务添加到全局队列)  
  2. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  3. dispatch_async(queue, ^{  
  4.       
  5.     //建立同步连接下载图片  
  6.     //图片网址  
  7.     NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";  
  8.     NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];  
  9.     UIImage *image = [UIImage imageWithData:data];  
  10.       
  11.     NSLog(@"同步连接下载图片,当前线程:%@",[NSThread currentThread]);  
  12.       
  13.     //在主线程中,显示下载的图像  
  14.     dispatch_async(dispatch_get_main_queue(), ^{  
  15.           
  16.         _imageView.image = image;  
  17.         NSLog(@"显示下载图片,当前线程:%@",[NSThread currentThread]);  
  18.           
  19.     });  
  20.       
  21. });  

         十 . 总结:

1.耗费时间的两种方式:下载(跟网速有关)和处理数据

2.  任务               线程           方法
  触发下载图片          主线程       didClick....Button
  建立同步连接下载图片   子线程        download

3.
/*
1.每个进程至少包含一个线程,这个默认创建的线程被成为主线程
2.单线程程序:程序只包含一个线程(主线程),线程中的代码按顺序执行,缺点:可能会造成主线程阻塞(有些任务耗时比较长)
3.多线程程序:程序中包含多个线程,线程是独立运行的,提高程序运行效率.
4.iOS开发中,所有跟UI有关的操作(绘制,刷新)都必须在主线程中完成.
5.子线程:主线程之外创建的新的线程

△.线程是可以设置优先级的
*/

4.
/*
△注意事项:
1.子线程中没有自动释放池,需要手动添加
2.NSThread创建的子线程,默认情况下,任务执行完成后,线程被关闭,销毁
3.在子线程中,NSTimer默认情况下,不会执行.如果在子线程中使用NSTimer,必须开启runLoop,方法如下:
4.所有线程都有runLoop,主线程默认是开启状态,子线程默认是关闭状态
5.子线程开启runLoop后,runLoop不停止,线程无法关闭
*/

//获取当前线程的runLoop,并开启
//    [[NSRunLoop currentRunLoop] run];
//获取当前线程的runLoop,并设定运行的时间
//    [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];

5.

/*

1.NSOperationQueue  操作队列(先进先出),可以管理多个操作对象.
2.NSOperationQueue  创建的多线程是可以重复使用的,是非脱离线程(线程中的任务完成后,线程进入睡眠状态,未被销毁;NSThread创建的线程是脱离线程)
3.NSOperationQueue  先加入队列的任务,先执行.(即"先进先出")
4.NSOperationQueue  控制的线程是并发执行的. 即:队列中的任务按照加入队列的顺序进行分派,但是下一个任务不用等待前一个任务完成再开始.多个任务可以同时执行,互不干扰.  ("并发"相对的是"串行")
5.什么叫线程同步?  线程A执行结束后才能执行线程B
6.NSOperationQueue如何实现线程同步?  把最大并发数设置为1,即:每次只允许一个线程执行任务
7.队列下载
*/

6.
△.注意:GCD不等于多线程


0 0
原创粉丝点击