随意细解:UI -- 多线程编程

程序

由源代码生成的可执行应用

进程

正在运行的一个应用程序,就是一个进程。每一进程都至少有一条线程,叫主线程。进程拥有独立运行所需的全部资源。
一个进程是由一个或多个线程组成。进程只负责资源的调度和分配。线程才是程序真正的执行单元,负责代码的执行。

线程

每一个线程都是独立的,可以执行任务。除了主线程以外的 都叫子线程 子线程可以有很多个,但是线程是耗费资源的(一般最多不超过5条 注:3条最佳)。 程序退出后,会清空线程的任务。

  • 主线程操作什么样的任务?
    UI界面、按钮点击、屏幕的滚动(一切用户看得到的,都要在主线程当中去操作)。比较大的耗时操作,又或者用户看不见的操作,可以放在子线程当中去做,比如,下载、解压缩、读取大型数据等 可以在子线程中操作。

  • 多线程的原理
    CPU在工作时 同一时间只能执行一个任务。之所以可以造成多条线程一起执行任务的假象,是CPU在进行高速的切换(调度),在线程之间切换,来达到多个任务一起执行的效果。

  • 多线程的优点
    1.可以大大提高执行任务的效率
    2.可以让用户有更好的用户体验

  • 多线程的缺点
    如果大量的开辟线程,会造成程序的卡顿,耗费过量的资源

  • 线程休眠

    [NSThread sleepForTimeInterval:5];

  • 判断当前线程是否是主线程

    [NSThread isMainThread]

  • 当前线程

    [NSThread currentThread]

开辟子线程

  1. performSelectorInBackground

    [self performSelectorInBackground:@selector(xxxx:) withObject:@"123"];

    方法是基类提供的,只要是对象,都能调用。

  2. 初始化开辟子线程

     NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(xxxx:) object:@"222"];
      [thread start];
  3. detachNewThreadSelector

     [NSThread detachNewThreadSelector:@selector(xxxx:) toTarget:self withObject:@"111"];

    这个方法不用开始,自动执行线程中的任务。

回到主线程

  1. performSelectorOnMainThread

    [self performSelectorOnMainThread:@selector(xxxxxx:) withObject:image waitUntilDone:NO];

    waitUntilDone : 是否等待回到主线程的方法执行完毕后再向下执行

  2. 获取主线程

    [self performSelector:@selector(xxxxxx:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];

多线程

  • 常用的开启多线程方法

    1.NSOperation 封装GCD的方法 提供OC的语法来使用GCD
    2.GCD 是苹果推荐的 可以最大化的发挥多核CPU 是C语言的函数

    使用GCD或者NSOperation,往合适的队列中添加任务 其他的 系统会根据队列的类型开启线程去完成任务。
    优势:不用程序员管理线程的生命周期

  • 线程队列
    (任务中心,可以执行很多任务)
    1.串行队列 主线程相当于一个串行队列 队列中的任务需要一个执行完毕后再执行下一个
    2.并行队列 队列中得任务进行并发执行 同时开始未必同时结束

    同步:没有开启子线程的能力
    异步:拥有开启子线程的能力

  • 线程之间的通信

    在子线程中 完成耗时的操作,完成后需要回到主线程进行UI刷新。
    主线程和子线程是独立的

NSOperation

NSOperation 是一个抽象类,使用子类NSInvocationOperation或NSBlockOperation来执行。

使用方法

创建一个队列,开启一个线程,把任务添加到队列中。需要把NSInvocationOperation对象放进一个队列里,才能开启子线程。

     // 创建一个队列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    // 给队列提供一个可以设置最大并发数
    // 一次最多并发执行2个任务
    queue.maxConcurrentOperationCount = 2;

    // 开启一个线程 (相当于 一个任务)
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad:) object:@"123"];
    // 把任务添加到队列中
    // 只需要把任务添加进队列中,不需要操作会自动执行
    // 不是添加一个任务 就开启一个线程
    // 这个操作是系统做的 有的线程会被系统重复利用(优化)

    [queue addOperation:operation];

    // 往队列中添加任务
    [queue addOperationWithBlock:^{
        // block中就是你要添加的任务
        NSLog(@"%@",[NSThread currentThread]);
    }];

    // 初始化任务
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        // 添加的任务
         NSLog(@"--- 4 --- %@", [NSThread currentThread]);
    }];
    // 添加进队列中
    [queue addOperation:blockOperation];

GCD

以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。GCD属于函数级的多线程,性能更高,功能更加强大。任务:具有一定功能的代码段。一般是一个block或者函数

  • 队列
    1.并行队列 系统提供的一个全局的并行队列(整个应用都可以使用) 如果不想用也可以创建一个出来
    2.串行队列 需要创建一个出来

  • 任务
    1.同步 不具备开启线程的能力
    2.异步 具有开启线程的能力

  • 分四种情况
    1.并行 —- 异步任务
    2.并行 —- 同步任务
    3.串行 —- 异步任务
    4.串行 —- 同步任务

并行 —- 异步任务 (重要)

// 开启子线程 并且任务并发
- (void)asyncGlobleQueue
{
    // 获取全局的并发队列
    // dispatch_queue_t 队列的类型
    // 参数1 是CPU切换的频率高度(切换的优先级)
    // 参数2 是个预留参数 可以填0
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 添加异步任务
    // 参数1 给哪个队列添加任务

    dispatch_async(queue, ^{
       // 添加任务的
        NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
    });
}

这里写图片描述

并行 —- 同步任务

// 没有开启子线程 相当于变成了一个串行的队列
- (void)syncGlobleQueue
{
    // 创建一个并行队列
    // 参数1 队列的标示符 反向域名 com.lanou3g.www
    // 参数2 填要创建的队列的类型(串/并)
    dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.www", DISPATCH_QUEUE_CONCURRENT);
    // 添加同步任务
    dispatch_sync(queue, ^{
          NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
    });

    // 创建的队列是需要释放的(ARC 不用释放)
    dispatch_release(queue);
}

这里写图片描述

串行 —- 异步任务

// 开启子线程 串行
- (void)asyncSericlQueue
{
    // 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("haha", DISPATCH_QUEUE_SERIAL);
    // 添加异步任务
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        // 添加任务的
        NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
    });
    dispatch_release(queue);
}

这里写图片描述

串行 —- 同步任务

// 没有开启线程 都在主线程 顺序执行
- (void)syncSericlQueue
{
    dispatch_queue_t queue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);
    // 添加同步任务
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务1 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务2 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务3 ----- %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----- 任务4 ----- %@", [NSThread currentThread]);
    });

    dispatch_release(queue);
}

这里写图片描述

多个线程对一个数据进行操作

解决方案: 访问数据,加一个锁,只能有1个线程访问。等这个线程访问结束后才能让下一个线程再访问,保证数据被访问的安全。

// 添加同步锁 (互斥锁)
self.lock = [[NSLock alloc]init];
[lock lock];  // 上锁

// 中间就是被上锁的部分

[lock unlock]; // 解锁

GCD开启线程 (重要)

GCD开启线程加载图片 回到主线程刷新UI

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        // 做请求 耗时操作 (同步请求)
        // 在子线程中 同步请求就相当于异步请求
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic24.nipic.com/20121022/9252150_193011306000_2.jpg"]];
        UIImage *image = [UIImage imageWithData:data];

        // 回到主线程 刷新界面
       // 取出主线程 dispatch_get_main_queue()
        dispatch_async(dispatch_get_main_queue(), ^{
            // 回到主线程要执行的任务
            // 刷新UI


        });

    });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值