多线程的简单使用

一、GCD、NSOperation、NSThread多线程

  1. GCD(Grand Central Dispatch)
    • 苹果开发的一个多核编程的解决方案,可以提高代码的执行效率与多核的利用率。
  2. NSOperation
    • NSOperation是面向对象的。
    • 不需要关心线程管理, 数据同步的事情,可以把精力放在自己需要执行的操作上
    • 相关的类是NSOperation,NSOperationQueue。
    • NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类: NSInvocationOperation和NSBlockOperation.
创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。
  3. NSThread
    • 缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。(NSThread的使用(本已过时)

二、GCD的简单使用

  • global 全局 | queue 队列 | async 异步 | sync 同步
 dispatch_get_global_queue
 dispatch_get_main_queue
  • 全局队列 dispatch_get_global_queue 可同步 可异步
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  • 串行队列 (是创建得到的,不能直接获取)只能同步
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
  • 主队列 dispatch_get_main_queue只能同歩
dispatch_async(dispatch_get_main_queue(), ^{      
   NSLog(@"main - > %@", [NSThread currentThread]);
    });
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
dispatch_apply执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
    // 执行5次
});
* TouchesBegan
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    // 主线程调用耗时操作(阻塞主线程,执行期间不能操作界面)
    //[self longTimeOperation];

    // [self CGD_Demo1];
    // [self CGD_Demo2];
    // [self CGD_Demo3];
    // [self GCDImage_Demo];

    [self NSOperation_Demo1];
    // [self NSOperation_Demo2];
    // [self NSOperation_Demo3];

}
//GCD_Demo调用方法
- (void)longTimeOperation{

    // 耗时操作
    for (NSInteger index = 0; index < 20; index++) {

        NSLog(@"耗时操作:%ld--%@",index,[NSThread currentThread]);
        if (index == 10) {
            NSLog(@"暂停,休息5秒");
            [NSThread sleepForTimeInterval:3];
        }
    }
    // 获得数据,返回主线程,更新UI
    [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
}

// 更新UI
- (void)updateUI{
    for (NSInteger index = 0; index < 5; index++) {
         NSLog(@"更新UI->%ld---当前线程->%@",index,[NSThread currentThread]);
    }

}
* GCD_Demo
-(void)demo1{
    // 创建队列 (串行)
    // DISPATCH_QUEUE_SERIAL 串行: 特点: 任务顺序执行
    // DISPATCH_QUEUE_CONCURRENT 并行 特点: 无序的
    dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
    // 添加任务
    dispatch_async(queue, ^{
        NSLog(@"任务1,%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"任务2");
        });

    });
    dispatch_async(queue, ^{
        NSLog(@"任务3");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务5");
    });
    [self loadData];

}
 - (void)loadData
{
    // 回到主线程刷新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"任务6---刷新UI");
        NSLog(@"current1 = %@, mainThread = %@", [NSThread currentThread], [NSThread mainThread]);
    });
}
 - (void)CGD_Demo2{

    /** 异步执行,开辟新线程
     *  dispatch_queue_t queue 队列,在哪儿执行
     *  block 任务
     */

    // 先获得全局队列(并发队列)
    dispatch_queue_t globleQ = dispatch_get_global_queue(0, 0);
    dispatch_async( globleQ , ^{
        // 耗时操作
        [self longTimeOperation];

        // 回到主线程,更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateUI];
        });
    });
}
// 调度组
// 例子:下载应用A\B,完成后并通知用户
 - (void)CGD_Demo3{

    // 创建组队列
    dispatch_group_t group = dispatch_group_create();

    // 创建任务1:
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"10秒之后,开始下载应用A-->当前线程:%@",[NSThread currentThread]);

    });
    // 创建任务2:
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2秒后,开始下载应用B-->当前线程:%@",[NSThread currentThread]);

    });

    // 线程完成后,通知更新UI
    // 用于监听所有任务的执行情况 [所以此功能代码必须放在所有任务之后进行书写]
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"下载完成-->当前线程:%@",[NSThread currentThread]);

        // 更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateUI];
        });
    });
}
  • Mark 一 使用GCD 开辟子线程请求数据,然后回到主线程刷新数据(展示图片)
// 
-(void)GCDImage_Demo{
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    imageView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.imageView];

    // 自己创建的
    // dispatch_async(dispatch_queue_create(@"myQueue", DISPATCH_QUEUE_CONCURRENT), <#^(void)block#>)


    // 系统方式
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

    dispatch_async(queue, ^{

        // ======处理数据库=======

        // 创建URL===
        NSURL *url = [NSURL URLWithString:@"http://img2.3lian.com/2014/f6/127/d/39.jpg"];
        // 转换成数据
        NSData *data = [[NSData alloc] initWithContentsOfURL:url];
        // 初始化
        UIImage *image = [[UIImage alloc] initWithData:data];
        if (data != nil) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // =====刷新界面======
                self.imageView.image = image;
            });
        }
        NSLog(@"current1 = %@, mainThread = %@", [NSThread currentThread], [NSThread mainThread]);
    });
}

三、NSOperation的简单使用

  • NSOperation的常用方法

【1】、start:开始方法,当把NSOperation添加到NSOperationQueue中去后,队列会在操作中调用start方法。
【2】、addDependency,removeDependency:添加从属性,删除从属性,比如说有线程a,b,如果操作a从属于b,那么a会等到b结束后才开始执行。
【3】、setQueuePriority:设置线程的优先级。
例:[a setQueuePriority:NSOperationQueuePriorityVeryLow];一共有四个优先级:
NSOperationQueuePriorityLow,
NSOperationQueuePriorityNormal,
NSOperationQueuePriorityHigh,
NSOperationQueuePriorityVeryHigh。
当你添加一个操作到一个队列时,在对操作调用start之前,NSOperationQueue会浏览所有的操作,具有较高优先级的操作会优先执行,具有相同优先级的操作会按照添加到队列中顺序执行。
【4】、setCompletionBlock:设置回调方法,当操作结束后,会调用设置的回调block。这个block会在主线程中执行。

* NSOperation_Demo
-(void)NSOperation_Demo1{
    // NSOperation不能直接进行多线程的创建,需要借助 :NSOperationQueue

    // 使用NSOperation的第一个子类去创建子线程 :NSInvocationOperation
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];

    // 在单独使用子NSOperation的子类去创建线程的时候,一定要启动
     [operation start];
    // 在使用NSOperation的子类去创建线程的时候,实际上线程没有真正意义上的创建

    // 使用NSOperation的第二个子类创建线程
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"我是block");
        NSLog(@"currentThread %@", [NSThread currentThread]);
        NSLog(@"%@", [NSThread mainThread]);

    }];

    // 只有启动的时候才会调用block中的内容
    [blockOperation start];

    // 需要把上面的两个线程,放到操作队列里
    // addOperation一旦创建的对象加入到操作对列中,就不能调用start,否则会崩溃
    //    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    //    [queue addOperation:operation];
    //    [queue addOperation:blockOperation];
}
- (void)test
{
    NSLog(@"test...");
    NSLog(@"currentThread == %@", [NSThread currentThread]);
    NSLog(@"mainThread == %@", [NSThread mainThread]);
}
-(void)NSOperation_Demo2{
    // 封装操作任务
    NSBlockOperation *operation_A = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载应用_Zip");
    }];
    NSBlockOperation *operation_B = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"解压zip——应用");
    }];

    NSBlockOperation *UI_Operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"更新UI");
    }];


    // 将任务添加到队列
    NSOperationQueue *globleQueue = [[NSOperationQueue alloc]init];//直接alloc/init 就是全局队列

    // 添加依赖关系,必须在将任务添加到队列之前(必须先将应用下载完毕后,在解压缩)
    [operation_B addDependency:operation_A];
    [UI_Operation addDependency:operation_B];

    // 添加任务到队列(->下载完成)
    // waitUntilFinished : YES 等待执行完成后再继续
    [globleQueue addOperations:@[operation_A,operation_B] waitUntilFinished:YES];

    // 更新UI
    [[NSOperationQueue mainQueue] addOperation:UI_Operation];

}
-(void)NSOperation_Demo3{
    // 创建队列的对象
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 最大的并发数量值
    // 当值设置为1的时候,可以叫做串行: 即顺序执行

    // 当值设置大于1的时候,叫做并行: 多条通道同时进行各自的任务
    queue.maxConcurrentOperationCount = 2;

    for (int i = 0; i < 10; i++) {
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

            NSLog(@"currentThread == %@", [NSThread currentThread]);
            NSLog(@"mainThread == %@", [NSThread mainThread]);
            NSLog(@"===%d", i);

        }];
        [queue addOperation:blockOperation];
    }

}

四、NSOprationQueue 与 GCD 的区别与选用容

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值