zoukankan      html  css  js  c++  java
  • IOS开发之多线程

    IOS开发之多线程

    1. 多线程简述

      什么是多线程? 解决的问题?

        多线程是指,编程中在主线程之外开辟的新线程,用于处理一些耗时的、并发的任务。使用多线程可以避免主线程的阻塞,

          也对一个线程不容易实现的任务提供了思路。在多线程的知识中也涉及队列,锁等概念。

        在这里科普一下队列的概念,队列:是管理线程的,相当于线程池,能管理线程什么时候执行。队列分为串行队列和并行队列。

        串行队列:队列中的线程按顺序执行(不会同时执行)

        并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。

              这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

         

        (1)pthred多线程(POSIX标准),用在类unix系统上。

        (2)NSThread   是对pthred面相对象封装

        (3)NSOperation/NSOperationQueue   是使用GCD实现的一套Objective-C的API

        (4)GCD(Grand Central Dispatch)   是基于C语言的底层API

          使用较多,因为:1.支持多核心 2.c和block接口,易使用 3.功能强

    2.NSThread

      2.1线程的创建 线程的控制和通信

        (1)创建线程
        [self createThread];
        
        (4) 线程的控制和通信
        实例: A线程执行到10得时候让B线程结束
    
    #pragma mark -- (1)创建线程
    #pragma mark -- (4) 线程的控制和通信
    -(void)createThread{
        //线程
        
        //顺序执行(串行执行)
        //[self taskA];
        //[self taskB];
    
        //并行执行(多个任务同时执行)
        //创建新的线程(第一种方式)---对应一个方法
        //注意:创建之后不会立即执行,需要start
        NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(taskA) object:nil];
        [thread1 start];
        
        //创建新的线程(方式2)
        //创建后会立即执行
        [NSThread detachNewThreadSelector:@selector(taskB:) toTarget:self withObject:thread1];
        
        
        
    }
    
    -(void)taskA{
        for (int i = 0; i < 20 ; i ++) {
            NSLog(@"A = %d",i);
            
            //每一次检测是否停止
            if ([NSThread currentThread].isCancelled) {
                //退出当前线程
                [NSThread exit];
            }
            
            //线程每次休眠时间为0.25s
            [NSThread sleepForTimeInterval:0.25];
        }
    }
    
    -(void)taskB:(NSThread *)thread{
        for (int i = 0; i < 20 ; i ++) {
            NSLog(@"B = %d",i);
            if ( i == 10) {
                //停止线程,发送cancle消息
                [thread cancel];
            }
            [NSThread sleepForTimeInterval:0.25];
    
        }
    }
    创建线程、线程的控制和通信

      2.2为什么使用多线程,解决什么样的问题

    #pragma mark -- (2)为什么使用多线程,解决什么样的问题
    -(void)whyUseThread{
    
        //本质: 多线程主要解决执行耗时任务出现UI界面阻塞的问题
        //      有时候为了同时执行多个任务(类似迅雷)
        //场景: 大麦网 -- 下载数据(耗时10s)
        //      图片(耗时5s)
        //      迅雷看看,加载1G视频文件
        //      数据库中加载1w条数据
        
        //演示
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        button.frame = CGRectMake(0, 20, 320, 40);
        [button setTitle:@"耗时任务" forState:UIControlStateNormal];
        [button addTarget:self action:@selector(startTask) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    }
    -(void)startTask{
        //http://10.0.8.8/download/真机调试.tar.gz
        //http://10.0.8.8/download/真机调试.tar.gz
        
        NSString *urlString = @"http://10.0.8.8/download/真机调试.tar.gz";
        NSData *data = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:urlString]];
        NSLog(@"size = %u",data.length);
    
    }
    为什么使用多线程,解决什么样的问题

      2.3使用通知监听线程的结束

    3)使用通知监听线程的结束
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(dealThreadExit) name:NSThreadWillExitNotification object:nil];
    #pragma mark -- (3)使用通知监听线程的结束
    -(void)dealThreadExit{
        NSLog(@"线程结束");
    }
    使用通知监听线程的结束

      2.4线程的同步和锁

        (5)线程的同步和锁
        演示问题:多个线程访问同一块内存
        为什么出问题
            CPU和内存(_num)
    
        //项目开发:nonatomic当一个属性只有UI界面访问可以加上,提高速度
        //  当这个属性页会被创建的子线程访问时不要加nonatomic保证线程的安全
        //
        //如何解决问题
        _lock = [[NSLock alloc]init];
    
        [NSThread detachNewThreadSelector:@selector(add) toTarget:self withObject:nil];
        [NSThread detachNewThreadSelector:@selector(sub) toTarget:self withObject:nil];
    
    #pragma mark -- (5)线程的同步和锁
    -(void)add{
        for (int i = 0; i <100; i++) {
            [_lock lock];
            _num ++;
            [_lock unlock];
            NSLog(@"add = %d",_num);
        }
    }
    
    -(void)sub{
        for (int i = 0; i <100; i++) {
            [_lock lock];
            _num --;
            [_lock unlock];
            NSLog(@"sub = %d",_num );
        }
        
    }
    线程的同步和锁

      2.5子线程如何更新UI

        (6)子线程如何更新UI(非常重要,不会代码会出现问题)
        //限制: UI线程称为主线程
        //      其他创建的线程称为工作子线程
        //      注意: 不要再子线程中直接操作UI(间接让主线程操作UI)
        //下载进度更新
        _progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(10, 200, 300, 20)];
        [self.view addSubview:_progressView];
        [NSThread detachNewThreadSelector:@selector(downloadNetworkdata) toTarget:self withObject:nil];
    
    #pragma mark -- (6)子线程如何更新UI(非常重要,不会代码会出现问题)
    -(void)downloadNetworkdata{
        for (int i = 0;  i< 100; i++) {
            //_progressView.progress +=.01;
            [self performSelectorOnMainThread:@selector(updataUI) withObject:nil waitUntilDone:YES];
            [NSThread sleepForTimeInterval:.1];
        }
    }
    
    -(void)updataUI{
        _progressView.progress +=.1;
        if (_progressView.progress == 1) {
            NSLog(@"=========");
            [_progressView removeFromSuperview];
        }
    }
    子线程如何更新UI

    3.NSOperation

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        //NSOperation 的使用 (操作、行动)
        //(1)什么是NSOperation,作用
        //      NSOperation和NSThread相似,实现多线程的一种机制
        //      在NSThread做了更高的抽象,加入了block,比NSThread更简单易用
        
        //NSOperation抽象类,使用NSInvocationOperation和NSBlockOperation
        
        //(2)NSInvocationOperation
        NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task1) object:nil];
        //注意: 创建后需要执行,执行的时候默认是同步的
    //    [invocationOperation start];
        
        //(3)NSBlockOperation
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i <20 ; i++) {
                NSLog(@"B = %d",i);
            }
    
        }];
    //    [blockOperation start];
        
        //(4)NSOperationQueue操作队列,理解为:任务列表
        //注意:任务会异步平行执行
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        [queue addOperations:@[invocationOperation,blockOperation] waitUntilFinished:NO];
        [queue addOperation:invocationOperation];
        [queue addOperation:blockOperation];
        
    }
    
    
    -(void)task1{
        for (int i = 0; i <20 ; i++) {
            NSLog(@"A = %d",i);
        }
    }

    4.GCD

      4.1GCD的使用 (Grand Central Dispatch 简写)

        好处:  1.支持多核心

               2.C和block接口, 易于使用

               3.较晚出现, 功能强大, 推荐使用

      4.2创建一个异步任务

    -(void)createAsyncTask
    {
        // 创建一个异步任务
        //参数1: 传入queue, 有三种queue
        //   main queue 主队列(UI主线程)
        //   global queue 全局队列(理解为工作线程)
        //   自定义的queue
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            for (int i=0; i<20; i++) {
                NSLog(@"A = %d",i);
            }
        });
        dispatch_async(queue, ^{
            for (int i=0; i<20; i++) {
                NSLog(@"B = %d",i);
            }
        });
        
    }

      4.3模拟网络下载

    -(void)simulateNetworkDownload
    {
        progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, 100, 300, 20)];
        [self.view addSubview:progressView];
        
        //GCD最简单开启异步任务的形式
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           
            for(int i=0; i<100; i++)
            {
                //子线程中不能直接更新UI
                //progressView.progress += 0.01;
                dispatch_async(dispatch_get_main_queue(), ^{
                    progressView.progress += 0.01;
                });
                
                NSLog(@"progress = %.2f%%",progressView.progress*100);
                
                [NSThread sleepForTimeInterval:0.1];
            }
            
            //最后显示对话框
            dispatch_async(dispatch_get_main_queue(), ^{
                UIAlertView *alertView = [[UIAlertView alloc] init];
                alertView.message = @"下载完成";
                [alertView addButtonWithTitle:@"取消"];
                [alertView show];
            });
            
        });
      
    }

      4.4只执行一次, 实现单例(推荐实现的方式,线程安全)

    -(void)runOnce
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"只执行一次的代码");
        });
    }

      4.5延时执行

    -(void)delayRun
    {
        //5s 后输出hehe
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"he he");
        });
        
        
    }

      4.6同时执行多个任务, 等待所有任务执行完成进行处理(类似迅雷

        实例:   迅雷所有任务完成之后自动关机

    -(void)groupRun
    {
        // group 任务组
        dispatch_group_t group = dispatch_group_create();
        
        //添加任务  7s完成
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i=0; i<100; i++) {
                NSLog(@"A = %d",i);
                [NSThread sleepForTimeInterval:0.07];
            }
        });
        
        // 5s完成
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i=0; i<100; i++) {
                NSLog(@"B = %d",i);
                [NSThread sleepForTimeInterval:0.05];
            }
        });
        
        // 10s完成
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i=0; i<100; i++) {
                NSLog(@"C = %d",i);
                [NSThread sleepForTimeInterval:0.1];
            }
        });
        
        dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"所有任务执行完成, 自动关机");
        });
        
    }

     

  • 相关阅读:
    Learning Deep CNN Denoiser Prior for Image Restoration阅读笔记
    图象恢复学习笔记(二)
    Alpha matting算法发展
    structure machine learning projects 课程笔记
    improve deep learning network 课程笔记
    convolutional neural network 课程笔记
    Ajax上传File对象到服务器
    SQL Server存储过程模拟HTTP请求POST和GET协议
    Jexus是一款Linux平台上的高性能WEB服务器和负载均衡网关
    Maven安装jar包到本地仓库
  • 原文地址:https://www.cnblogs.com/BadMao/p/4439422.html
Copyright © 2011-2022 走看看