UI课程22 多线程、GCD

1.多线程
多线程并不是真正的开辟了多个线程,而是处理器一会儿执行这个,一会又执行那个,处理器在多线程之间切换,给人一个假象好像有多个线程。
2、程序,进程、线程之间的关系
程序:有代码生成的可执行应用(如:QQ.app)
进程:就是正在运行的程序(如正在运行的QQ),进程拥有独立运行所需的所有资源
线程:程序中独立运行的代码段。(如:接收QQ消息的代码)
注意:一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是真正的执行单元,负责代码的执行。
3.线程
(1)单线程:只有一个主线程的程序。
主线程:每个正在执行的程序(进程)至少包含一个线程,这个线程就是主线程。主线程在程序启动时被创建,用于执行main函数。
负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等),这些代码只能顺序执行,无法并发执行。
**注意:**UI刷新和添加必须写在主线程中

子线程:相对主线程来讲,开辟的新的线程。
子线程和主线程都是独立运行的单元,各自的执行互不影响,可以并发执行。
有效避免了代码阻塞,提高程序的运行性能。

A. iOS默认给主线程分配1M的空间,默认给子线程分配512K的空间(分配字节数必须是4K的整数倍),开辟的空间用来存放线程中为变量开辟的空间,一般情况下足够使用。
B. 与栈空间的使用方式不同,主线程和子线程共用一块堆空间
C. 程序入口处默认设置了自动释放池(main函数),由主线程负责执行代码,子线程开辟的内存不在主线程管理的范围内(线程间互不干扰,相互独立),所以子线为对象开辟的空间不会被自动释放,需手动释放(手动书写自动释放池)

(2)
多线程种类:
1)脱离线程:线程结束后被销毁(如下载)
2)非脱离线程:线程结束后被挂起,等待唤醒,不销毁(如:通话功能)
(主线程一定是非脱离线程)

iOS实现多线程的种类:
1)NSObject
2)NSThread
3)NSOperation、NSOperationQueue
4)GCD

注意:在MVC中属于M,不能直接使用,而是使用子类NSInvocationOperation或NSBlockOperation,它本身无主线程,子线程之分,可在任意线程中使用,通常 与NSOperationQueue结合使用
1)NSInvocationOperation封装了执行操作的target和要执行的action
2)NSBlockOperation封装了要执行的代码块

#pragma mark - NSObject 多线程方式(主线程)

    [self performSelectorInBackground:@selector(calculate:) withObject:@"参数"];//withObject:需要传递的参数,不传参时就不用写


#pragma mark - NSThread 多线程方式

    //方式一(需要开启)
//    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(calculate:) object:nil];
//    [thread1 start];//手动开启

    //方式二
    [NSThread detachNewThreadSelector:@selector(calculate:) toTarget:self withObject:nil];


#pragma mark - NSOperation  多线程方式(只是一个操作,并不代表是主线程(calculate中输出1))

    //方式一:NSInvocationOperation
    NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(printNum) object:nil];
//    [invocation start];//手动启动

    //方式二
    __weak typeof(self) temp = self;
    NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
        [temp printAnotherNum];

    }];
    //[block start];

    //创建一个操作队列,向队列中添加操作(可添加多个不同的invocation或block),完成多任务同时执行
    //一个队列可以放多个线程,一个队列也可放到某个线程中执行
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
#warning 注意:一定提前设置好并发数(设置到后面的话不起作用)
    [queue setMaxConcurrentOperationCount:2];//最大并发数为1,表示串行,一个一个执行
    [queue addOperation:invocation];
    [queue addOperation:block];


//子线程
- (void)calculate:(id)sender{

    @autoreleasepool{ //释放池
        NSArray *array = @[@1,@2,@3,@4,@5];
        for (int i = 0; i < 23; i ++) {
            array = [array arrayByAddingObjectsFromArray:array];
        }
        self.view.backgroundColor = [UIColor cyanColor];

        NSLog( @"-----%@",sender);
        NSLog( @"%d",[NSThread isMainThread]);//是不是主线程
    }
}

可以判断是不是主线程:

   NSLog( @"%d",[NSThread isMainThread]);//判断是不是主线程

4.GCD
GCD:(Grand Central Dispatch )属于函数级的多线程
1)任务:具有一定功能的代码段,一般是一个block或者函数
2)分发队列:以队列的方式工作 ,先进先出
3)会根据分发队列的类型,创建合适数量的线程执行队列中的任务。
(1)GCD中有两种队列
1)SerialQueue:一次只执行一个任务。用于同步访问特定的资源或数据,当创建多个SerialQueue时,虽然他们各自是同步执行的,但SerialQueue与SerialQueue之间是并发执行的。
SerialQueue能实现同步
2)Concurrent:可以不会ing发执行多个任务,但是遵守先进先出

(2)GCD功能
1)dispatch_async() //往队列中添加任务,任务会排队执行
2)dispatch_after() //往队列里添加任务,任务排队切且在延迟的时间点执行
3)dispatch_apply() //网队列添加任务,任务会重复执行N次

4)dispatch_group_async() //将任务添加到队列中,并添加分组标记
5)dispatch_group_notify() //将任务添加到队列中,当某个分组的所有任务执行完后,此任务才会执行
6)dispatch_barrier_async() //将任务添加到队列中,此任务执行的时候,其他任务停止执行(前提是自定义并行队列)

7)dispatch_once() //将任务添加到队列中,但任务在程序运行中值执行一次
8)dispatch_sync() //将任务添加到队列中,block 不执行完,下面代码不会执行
9)dispatch_async_f() //将任务添加到队列中,任务是函数非block

详情在以下代码注释中:

#pragma mark - GCD

    //1.主队列:是串行队列
    //2.全局队列:是并行队列
    //3.自定义队列(串行队列,并行队列)


    //主队列和全局队列都是单例,主队列串行,全局队列并行

#pragma 主队列
    /*
    //获取主队列(dispatch_queue_t 是所有队列的类型)
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    //向主队列添加任务
    dispatch_async(mainQueue, ^{

        NSLog(@"第一个任务");
    });

    dispatch_async(mainQueue, ^{
        NSLog( @"第二个任务");
    });

    dispatch_async(mainQueue, ^{
        NSLog(@"第三个任务");
    });

    //设置延时执行(延时器)  不要给主队列(串行)添加延时器   (自动提示中,只要有snippet,则会自动完成很多空缺的内容)
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC));//从当前开始,10秒后执行
    dispatch_after(time, mainQueue, ^{

        NSLog(@"这是十年后的你");
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), mainQueue, ^{
        NSLog(@"这是5年后的你");
    });

//    dispatch_apply(3, mainQueue, ^(size_t t) {
//       
//        NSLog(@" BE HAPPY ! %zi",t);
//    });
*/

#pragma 全局队列
/*
    //获取全局队列
    //DISPATCH_QUEUE_PRIORITY_DEFAULT 优先级(默认)
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //向队列中添加任务(并行)
    dispatch_async(globalQueue, ^{
        NSLog(@"111111111111111");
    });

    dispatch_async(globalQueue, ^{
        NSLog(@"22222222222");
    });

    dispatch_async(globalQueue, ^{
        NSLog(@"33333333333333");
    });

    //重复执行某一个任务
    dispatch_apply(3, globalQueue, ^(size_t t) { //并行执行3遍

        NSLog(@"重要的是说三遍 %zu",t);
    });


    //分组任务
    dispatch_group_t group = dispatch_group_create();

    //向分组中添加任务
    dispatch_group_notify(group, globalQueue, ^{

        NSLog(@"最后一个");
    });//和添加到队列的位置有关,当处于队列末尾的时候,最后执行


    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"第一分组第一小队");
    });

    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"第一分组第二小队");
    });

    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"第一分组第三小队");
    });



    dispatch_barrier_async(globalQueue, ^{

        int sum = 0;
        for (int i = 0; i < 635500000; i ++) {
            sum += i;
        }
        NSLog(@"执行完成");
    });
*/


    //此函数添加到队列的任务,需要等其执行完后才可以执行其他队列的任务
    //前提:自定义并行队列
   //dispatch_barrier_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

#pragma 自定义队列
    //自定义串行队列
    /*
    //第一个参数:队列表示符,可以获取到某一队列的标示符
    //第二个参数:队列的类型(串行或者并行)
    dispatch_queue_t serialQueue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);

    //添加task
    dispatch_async(serialQueue, ^{
        NSLog(@"第一个任务");
    });

    dispatch_async(serialQueue, ^{
        NSLog(@"第二个任务");
    });

    dispatch_async(serialQueue, ^{
        NSLog(@"第三个任务");
    });

    //获取队列的标示符
    const char *str = dispatch_queue_get_label(serialQueue);
    NSLog(@"%s",str);
     */


    //自定义并行队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^{
        NSLog(@"1");
    });

    //必须等sync(如同串行)执行完,余下的队列任务才可以执行
    dispatch_sync(concurrentQueue, ^{
        int sum = 0;
        for (int i = 0; i < 63500000; i ++) {
            sum += i;
        }
        NSLog(@"执行");
    });

    //必须等barrier(阻塞的意思)函数执行完,余下的队列任务才可以执行
    dispatch_barrier_async(concurrentQueue, ^{
        int sum = 0;
        for (int i = 0; i < 63500000; i ++) {
            sum += i;
        }
        NSLog(@"哈哈哈");
    });

    dispatch_async(concurrentQueue, ^{
        NSLog(@"2");
    });
    dispatch_async(concurrentQueue, ^{
        NSLog(@"3");
    });


    //GCD可以使用此函数,向队列中添加函数,让函数执行
    //函数类型  void (*)(void *) 任何类型都可以传进来
    dispatch_async_f(concurrentQueue, "string", function);//string 是function函数的参数

    //dispatch_once添加的任务,在整个程序运行期间只会执行一次(重复添加无效)(只会打印出一个)
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"哈哈哈");
    });
    dispatch_once(&onceToken, ^{
        NSLog(@"哈哈哈");
    });
    dispatch_once(&onceToken, ^{
        NSLog(@"哈哈哈");
    });

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值