多线程 - 课程分析

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

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


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

     NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);


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

-(void)cycle
{
    //获取当前线程,判断是否是主线程
    NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    int sum = 0;
    for (int i=0; i<500; i++) {
        sum += i;
//        NSLog(@"%d",i);
    }
//    NSLog(@"%d",sum);
}

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

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

    [NSThread detachNewThreadSelector:@selector(cycle) toTarget:self withObject:nil];


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


    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(cycle) object:nil];
    [thread start];

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

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


//在子线程中,同步连接下载图片
-(void)downloadImage:(NSString *)url
{
    
    //在子线程中,使用同步方式下载图片.  △备注:在子线程中,不要使用异步连接,会出现问题
    
    /*
     △注意事项:
     1.子线程中没有自动释放池,需要手动添加
     2.NSThread创建的子线程,默认情况下,任务执行完成后,线程被关闭,销毁
     3.在子线程中,NSTimer默认情况下,不会执行.如果在子线程中使用NSTimer,必须开启runLoop,方法如下:
     4.所有线程都有runLoop,主线程默认是开启状态,子线程默认是关闭状态
     5.子线程开启runLoop后,runLoop不停止,线程无法关闭
     */
    
    //获取当前线程的runLoop,并开启
//    [[NSRunLoop currentRunLoop] run];
    //获取当前线程的runLoop,并设定运行的时间
//    [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
    
    
    //获取当前线程,判断是否是主线程
    NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    
    //同步下载图片
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    //将data转换成image对象
    UIImage *image = [UIImage imageWithData:data];
    
    //△注意:将image在主线程中进行显示.
//    _imageView.image = image;//这句话位置不对,不能写在这里
    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];//第三个参数:等待子线程任务执行完成,再回到主线程执行
    
    //直接给imageView附图片
//    [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    
}
//在主线程中,将image显示在imageView上
-(void)showImage:(UIImage *)image
{
    //获取当前线程,判断是否是主线程
    NSLog(@"当前线程 %@ ------ 是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    //参数image是从子线程中返回
    _imageView.image = image;
    
}

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

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

       五 . block方法:

    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"当前线程 %@ ----- 是否是主线程:%d", [NSThread currentThread], [NSThread isMainThread]);
        
        for (int i = 1; i < 500; i++) {
            
        }
    }];
    
    [operation start];

       六 . NSOperationQueue :

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

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

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

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


//串行队列 第一种实现:使用主队列
    /*
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    //向队列异步添加任务
    dispatch_async(queue, ^{
        NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    */
     
    //串行队列 第二种实现:使用自定义串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    
    //释放(注意:MRC下需要释放)
//    dispatch_release(queue);

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

    //并发队列 第一种实现:全局队列
    /*
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    */
    
    //并发队列 第二种实现:使用自定义并发队列
    
    dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"第一个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五个任务,所在线程:%@,是否是主线程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });

         九 . GCD

    //在子线程中建立同步连接下载图片(把任务添加到全局队列)
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        
        //建立同步连接下载图片
        //图片网址
        NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
        UIImage *image = [UIImage imageWithData:data];
        
        NSLog(@"同步连接下载图片,当前线程:%@",[NSThread currentThread]);
        
        //在主线程中,显示下载的图像
        dispatch_async(dispatch_get_main_queue(), ^{
            
            _imageView.image = image;
            NSLog(@"显示下载图片,当前线程:%@",[NSThread currentThread]);
            
        });
        
    });

         十 . 总结:

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值