zoukankan      html  css  js  c++  java
  • iOS-多线程之GCD(原创)

    前言

    GCD

    全称 Grand Central DisPath NSOperation便是基于GCD的封装

     

    基础知识

    1.GCD的优势

     (1)为多核的并行运算提出了解决方案

     (2)GCD会自动利用更多的CPU内核 比和双核 四核

     (3).GCD自动管理线程的生命周期(创建线程 调度任务 销毁线程)

     (4).程序员只需告诉GCD想要执行什么任务 不需要编写任何线程管理代码

     

     2.GCD中有2个核心概念

     任务: 执行什么操作

     队列: 用来存放任务

     

     3.队列可以分为两大类型

     串行队列(Serial Dispatch Queue):只有一个线程,加入到队列中的操作按添加顺序依次执行,一个任务执行完毕后,才能再执行下一个任务。

     并发队列(Concurrent Dispatch Queue):有多个线程,操作进来以后他会将这些线程安排在可用的处理器上,同时保证先进来的任务优先处理。

     其实在GCD中还有一个特殊队列就是主队列 主队列中永远只有一个线程-主线程 用来执行主线程的操作任务

     

     4.采用GCD做多线程 可以抽象分为二步

     (1)找到队列(主队列或串行队列或并行队列)

     (2)在队列中用同步或者异步的方式执行任务

     

     5.执行队列中的任务的二种方式

     (1)同步 只能在当前线程执行任务 不具备开启新线程的能力--主线程

     (2)异步 可以在新的线程中执行任务 具备开启新线程的能力--子线程

     

    下面介绍一下串行 并行 同步 异步 

    - (void)viewDidLoad {

        [super viewDidLoad];

        self.view.backgroundColor = [UIColor whiteColor];

        // Do any additional setup after loading the view, typically from a nib.

    #pragma mark ====串行同步====

        

    //    //1.找到队列 第一个参数:该队列的名字 第二个参数:指定队列的类型

    //    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

    //    //2.给队列指定任务 第一个参数:任务在哪个队列中执行 第二个参数:想要执行的操作

    //    //asyn是异步 syn是同步

    //    dispatch_sync(serialQueue, ^{

    //        NSLog(@"1===%@",[NSThread currentThread]);

    //    });

    //    

    #pragma mark ====串行异步====

    //    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

    //    dispatch_async(serialQueue, ^{

    //        NSLog(@"1===%@",[NSThread currentThread]);

    //    });

    #pragma mark ====并行同步====

    //    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

    //    dispatch_sync(concurrentQueue, ^{

    //        NSLog(@"1===%@",[NSThread currentThread]);

    //    });

    #pragma mark ====并行异步====

            dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

            dispatch_async(concurrentQueue, ^{

                NSLog(@"1===%@",[NSThread currentThread]);

            });

    }

    此时我们新建一个类来看一下 用GCD的形式来加载网络图片让它显示在self.view上 我这里为它命名为OneImageViewController  效果图以及.m代码如下

    #import "OneImageViewController.h"
    #define kurl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"
    @interface OneImageViewController ()
    {
        UIImageView *imageView;
    }
    @end
    
    @implementation OneImageViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        /*
         1.创建视图
         2.创建一个串行队列
         3.用异步方式执行队列中的任务
         4.加载网络资源
         5.回到主线程 更新UI
         
         
         */
        //1.创建视图
        imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
        [self.view addSubview:imageView];
        //2.创建一个串行队列
        dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
        //3.用异步方式执行队列中的任务
        dispatch_async(serialQueue, ^{
            //4.加载网络资源
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kurl]];
            UIImage *image = [UIImage imageWithData:data];
            //5.回到主线程 dispatch_get_main_queue这个函数 找到主队列
            dispatch_queue_t mainQueue = dispatch_get_main_queue();
            dispatch_sync(mainQueue, ^{
               //6.更新UI
                imageView.image = image;
            });
            
        });
    
    
    }
    @end
    

      

    利用GCD加载多张网络图片 我在这里给类命名为MoreImageViewViewController 效果图以及.m代码如下

    #import "MoreImageViewViewController.h"
    #define kurl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"
    @interface MoreImageViewViewController ()
    {
        int imageIndex;
        dispatch_queue_t concurrentQueue;
        
    }
    @end
    
    @implementation MoreImageViewViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        self.edgesForExtendedLayout = UIRectEdgeNone;
        /*
         1.创建多个视图
         2.找到并行队列
         3.给这个并行队列指定多个任务
         4.在子线程加载网络资源
         5.回到主线程
         6.更新UI
         */
        
        imageIndex = 100;
        
        //1.创建多个视图
        for (int row = 0; row<3; row++) {
            for (int list = 0; list<2; list++) {
                
                UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(10+list*200, 10+row*200, 180, 180)];
                
                //imageView.backgroundColor = [UIColor orangeColor];
                
                 imageView.tag = imageIndex++;
                
                [self.view addSubview:imageView];
                
            }
        }
        //2.找到并行队列 dispatch_get_global_queue 获取到系统的全局并列队列
        
        //第一个参数:是优先级 第二个参数:保留参数 没用
    //    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(0, 0);
        
          concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_SERIAL);
        
        //3.给这个并行队列指定多个任务
        for (int index = 0; index<6; index++) {
            dispatch_async(concurrentQueue, ^{
                [NSThread sleepForTimeInterval:0.5];
                //4.加载网络资源
                NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kurl]];
                UIImage *image = [UIImage imageWithData:data];
                //5.回到主线程
                dispatch_sync(dispatch_get_main_queue(), ^{
                    //6.更新UI
                    UIImageView *imageView = [self.view viewWithTag:100+index];
                    imageView.image = image;
                });
    
            });
        }
        
        [self controlBtn];
    }
    
    - (void)controlBtn{
        
        
        UISegmentedControl *segment = [[UISegmentedControl alloc]initWithItems:@[@"暂停",@"开启",]];
        
        segment.frame = CGRectMake(50, 620, 300, 50);
        
        segment.apportionsSegmentWidthsByContent = YES;
        
        [self.view addSubview:segment];
        
        [segment addTarget:self action:@selector(clickSegment:) forControlEvents:UIControlEventValueChanged];
    }
    
    - (void)clickSegment:(UISegmentedControl *)sender {
        
        switch (sender.selectedSegmentIndex) {
                
            case 0:{
                //暂停队列
                dispatch_suspend(concurrentQueue);
            }break;
                
            case 1:{
                //恢复队列
                dispatch_resume(concurrentQueue);
                
            }break;
                
        }

    开发中我们可能会用到线程锁 比如购票抢票这一功能  

    没线程锁的情况下: 我走进购票大厅,买票的人都没有排队,我好不容易挤到窗口前,正打算掏钱买票的时候,旁边有人已经把钱给了售票员。虽然你的线程已经开始执行买票的方法,但当你去拿票时,也就是将票数减一时,CPU将你的线程给中断,开始执行其他的线程,CPU返回继续执行你的线程的时候,票已经没了。

    有线程锁的情况下:* 我走进购票大厅,买票的人都在排队,当我到柜台能保证我买票的关键过程,也就是报站、掏钱、拿票过程不受干扰,我采用线程锁将这个关键过程给锁起来,以保证我能顺利的买到票。

    我在这里命名为GCDLockViewController 具体.m代码如下

    #import "GCDLockViewController.h"
    
    @interface GCDLockViewController ()
    {
        NSLock *mylock;
    }
    @end
    
    @implementation GCDLockViewController
    - (void)viewDidLoad {
        
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor whiteColor];
        //实例化一个线程锁
        mylock = [NSLock new];
    #pragma mark ====线程锁====
        __block int ticketNum = 10;
        dispatch_queue_t concurrent = dispatch_get_global_queue(0, 0);
        for (int index = 0; index<15; index++) {
            dispatch_async(concurrent, ^{
                
    //            [mylock lock];
    //            if (ticketNum>0) {
    //                ticketNum--;
    //                NSLog(@"还剩%d张票",ticketNum);
    //            }
    //            [mylock unlock];
                //参数一般是self 与self相关的变量 多个线程同时同时只访问一次
                @synchronized(self) {
                    if (ticketNum>0) {
                                        ticketNum--;
                                        NSLog(@"还剩%d张票",ticketNum);
                                    }
    
                }
                
                
                
            });
        }
        
    
    }
    @end
    

     

     

     

  • 相关阅读:
    Mac php使用gd库出错 Call to undefined function imagettftext()
    centos 使用 locate
    Mac HomeBrew 安装 mysql
    zsh 命令提示符 PROMPT
    新的开始
    Java 面试题分析
    Java NIO Show All Files
    正确使用 Volatile 变量
    面试题整理 2017
    有10阶梯, 每次走1,2 or 3 阶,有多少种方式???
  • 原文地址:https://www.cnblogs.com/start-ios/p/5328488.html
Copyright © 2011-2022 走看看