美文网首页
iOS多线程的一些知识点

iOS多线程的一些知识点

作者: Rathen | 来源:发表于2017-11-12 22:21 被阅读43次

讲述一些有关iOS中的多线程知识点,以及一些应用实例

一、多线程基础知识

多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。

进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间;

线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程;

任务(task)用于指代抽象的概念,表示需要执行工作。

任务分为同步任务与异步任务,它们的区别是:

同步任务优先级高,在线程中有执行顺序,不会开启新的线程。

异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其他队列会开启新的线程。

队列:一种先进先出的数据结构,线程的创建和回收不需要程序员操作,由队列负责。

串行队列:队列中的任务只会顺序执行(类似跑步)

并行队列:队列中的任务通常会并发执行(类似赛跑)

全局队列:是系统开发的,直接拿过来(get)用就可以;与并行队列类似,但调试时,无法确认操作所在队列

主队列:每一个应用程序对应唯一一个主队列,直接get即可;在多线程开发中,使用主队列更新UI

iOS中的三种多线程技术

1、NSThread

(1)创建一个线程很简单

(2)需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

2、GCD--Grand Central Dispatch

(1)基于C语言的API

(2)使用block来定义任务,简洁灵活

(3)提供了更多的控制能力以及操作队列中所不能使用的底层函数

3、NSOpreation

(1)纯OC代码 操作队列,对GCD的封装.它是一个抽象类,只能继承它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

(2)是面向对象的线程技术

(3)提供了一些在gcd中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系

二、线程的使用

1、NSThread

NSThread的创建
 //第一种方式
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction) object:nil];
[thread start];
//第二种方式
[NSThread detachNewThreadSelector:@selector(threadAction) toTarget:self withObject:nil];
//第三种方式 不安全 不建议使用
[self performSelectorInBackground:@selector(threadAction) withObject:nil];
NSThread的暂停
//第一种 把这段代码放进selector 线程执行的方法中
//延迟100S后执行后面的代码
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:100]];
NSThread的取消
[thread cancel];
线程之间的通信
// 在指定线程上执行操作
[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES]; 
//在主线程中执行操作
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];  
//在当前线程中执行操作
[self performSelector:@selector(run) withObject:nil];
实例 - 下载图片
- (void)downLoadImage {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download) object:nil];
[thread start];
 }
- (void)download {
NSLog(@"download ---- %@", [NSThread currentThread]);

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"地址"]];
UIImage *image = [UIImage imageWithData:data];
if (image) {
    [self performSelectorOnMainThread:@selector(reloadImageView:) withObject:image waitUntilDone:YES];
} else {
    NSLog(@"图片未下载成功");
}
}

- (void)reloadImageView:(UIImage *)image {
self.imageView.image = image;
}

GCD

GCD任务执行
//添加异步操作 无需等待
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
//添加同步操作 等待任务执行完毕
dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
栅栏函数
dispatch_barrier_sync(dispatch_queue_t queue,
    DISPATCH_NOESCAPE dispatch_block_t block);
//用法 注意:栅栏函数不能使用全局并发队列  只能用自己创建的并发队列
dispatch_queue_t queue = dispatch_queue_create("zhalan", DISPATCH_QUEUE_CONCURRENT);
/*
 1、封装任务
 2、把任务添加到队列中
 */
dispatch_async(queue, ^{
    NSLog(@"当前线程1----%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"当前线程2----%@",[NSThread currentThread]);
});

//栅栏函数(异步使用,同步没必要)
dispatch_barrier_sync(queue, ^{
    NSLog(@"+++++++++++++栅栏+++++++++++++++++");
});
dispatch_async(queue, ^{
    NSLog(@"当前线程3----%@",[NSThread currentThread]);
});


打印结果
2017-11-13 22:58:05.338419+0800 GCD[1299:75762] 当前线程2----<NSThread: 0x60000026cec0>{number = 4, name = (null)}
2017-11-13 22:58:05.338419+0800 GCD[1299:75922] 当前线程1----<NSThread: 0x60000026db00>{number = 5, name = (null)}
2017-11-13 22:58:05.338703+0800 GCD[1299:74941] +++++++++++++栅栏+++++++++++++++++
2017-11-13 22:58:05.339223+0800 GCD[1299:75922] 当前线程3----<NSThread: 0x60000026db00>{number = 5, name = (null)}
快速迭代(for循环)
//for循环是同步的  是同步线程循环的
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/**
 GCD的快速迭代
 第一个参数:次数
 第二个参数:队列,只能传并发队列,传主队列会发生死锁,传串行队列的话没有作用
 第三个参数:就像for中的i  索引
  */
//速度快  内部开子线程 由子线程并发执行 和主线程 一起完成遍历任务,任务执行时并发的 无顺序的
dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"快速迭代: %zd  %@", index ,[NSThread currentThread]);
});
队列组
//和栅栏函数比较像
//监听这一组中的其他队列 等到全部队列完成最后执行
//1、创建队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//2、创建队列组
dispatch_group_t group = dispatch_group_create();
//3、异步执行
/*
 1、封装任务
 2、把任务添加到队列中
 3、监听任务的情况,通知group
 */
dispatch_group_async(group, queue, ^{
    NSLog(@"队列组1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"队列组2");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"队列组3");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"队列组4");
});
//拦截通知,当队列组中所有任务都执行完毕的时候,会进入到下面的方法
dispatch_group_notify(group, queue, ^{
    NSLog(@"队列组执行完毕");
});
队列组(旧方法)
//1、创建队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//2、创建队列组
dispatch_group_t group = dispatch_group_create();

//3、该方法后边的异步任务中,会被纳入的队列组的监听范围中
dispatch_group_enter(group);

dispatch_async(queue, ^{
    NSLog(@"队列组不同写法1");
    //4、退出队列组
    dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"队列组不同写法2");
    //4、退出队列组
    dispatch_group_leave(group);

});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"队列组不同写法3");
    //4、退出队列组
    dispatch_group_leave(group);

});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"队列组不同写法4");
    //4、退出队列组
    dispatch_group_leave(group);

});

//拦截通知
//该方法是同步的还是异步的??(内部本身是异步的,不是阻塞的)
//    dispatch_group_notify(group, queue, ^{
//        NSLog(@"队列组执行完毕");
//    });

//也可以用这个拦截通知
//第二个参数中的宏  DISPATCH_TIME_FOREVER  直到全部完成才执行
//本身是阻塞的
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"_______end _________");
使用队列组下载图片实例
  dispatch_queue_t queue =  dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
//1、下载图片
dispatch_group_async(group,queue, ^{
    //1.1确定url
    NSURL *url = [NSURL URLWithString:@""];
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    self.image1 = image;
    NSLog(@"下载一张图片");
});
dispatch_group_async(group, queue, ^{
    NSURL *url = [NSURL URLWithString:@""];
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:imageData];
    self.image2 = image;
    NSLog(@"下载第二张图片");
});
//2.合成图片

dispatch_group_notify(group, queue, ^{
    //2.1 创建一张图形上下文
    UIGraphicsBeginImageContext(CGSizeMake(200, 200));
    //2.2 画图
    [self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
    self.image1 = nil;
    [self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
    self.image2 = nil;
    //2.3 根据上下文得到一张图片
    UIImage *image =  UIGraphicsGetImageFromCurrentImageContext();
    //2.4 关闭图片上下文
    UIGraphicsEndImageContext();
    //3显示图片  回到主线程
    dispatch_async(dispatch_get_main_queue(), ^{
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 200, 200)];
        imageView.image = image;
        [self.view addSubview:imageView];
        NSLog(@"合成图片  更新UI  %@", [NSThread currentThread]);
    });
    
});
定时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
    NSLog(@"执行定时器");
});
dispatch_resume(timer);



dispatch_suspend(self.timer);//暂停
dispatch_source_cancel(self.timer);//取消
GCD中线程之间的通信
dispatch_async(dispatch_get_main_queue(), ^{
   //返回主线程
});

NSOperation

NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoad1) object:nil];
[op1 start];
//未加入队列 是在主线程执行的
NSBlockOperation
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务1___  %@",[NSThread currentThread]);
}];
[op1 start];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务2___  %@",[NSThread currentThread]);
}];
[op2 start];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务3___  %@",[NSThread currentThread]);
}];

//上面的当前线程都是主线程 下面的实在子线程中执行

//addExecutionBlock  追加方法  在子线程中添加
[op3 addExecutionBlock:^{
    NSLog(@"____任务4___  %@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
    NSLog(@"____任务5___  %@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
    NSLog(@"____任务6___  %@",[NSThread currentThread]);
}];
[op3 start];
NSOperationQueue
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoad1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoad1) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoad1) object:nil];

/*
 GCD中
 1、串行队列 create和主队列
 2、并发队列 create和全局并发队列glob
 NSOperation中
 1、主队列:[NSOperationQueue mainQueue] 和GCD中的主队列一样的  串行队列
 2、非主队列:[[NSOperationQueue alloc] init] 同时具有串行和并发队列的功能(默认情况下是并发)
 */
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];

//addOperation默认调用了 start方法

//上面是NSInvocationOperation    下面是使用NSBlockOperation
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务1___  %@",[NSThread currentThread]);
}];

NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务2___  %@",[NSThread currentThread]);
}];

NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务3___  %@",[NSThread currentThread]);
}];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
NSOperation的继承用法
 ZRSOperation *op1 = [[ZRSOperation alloc] init];
ZRSOperation *op2 = [[ZRSOperation alloc] init];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];

//下面是ZRSOperation文件
//.h文件中
#import <Foundation/Foundation.h>

@interface ZRSOperation : NSOperation

@end
 //.m文件中
 #import "ZRSOperation.h"

@implementation ZRSOperation

  //执行任务的时候要重写main方法  告知要执行的任务是什么
  //好处 有利于代码隐蔽, 有利于代码复用
- (void)main {
[super main];
//将封装的任务 放进去
NSLog(@"main-----%@", [NSThread currentThread]);

NSLog(@"++++++++++++++++++++++=");
for (int i = 0; i < 10000; i ++) {
    NSLog(@"download1---- %zd", i);
}
//解决自定义的 取消不能用
if (self.cancelled) {
    return;
}
NSLog(@"++++++++++++++++++++++=");
for (int i = 0; i < 10000; i ++) {
    NSLog(@"download2---- %zd", i);
}
if (self.cancelled) {
    return;
}
NSLog(@"++++++++++++++++++++++=");
for (int i = 0; i < 10000; i ++) {
    NSLog(@"download3---- %zd", i);
}
}

@end
添加操作依赖
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务1___  %@",[NSThread currentThread]);
}];

NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务2___  %@",[NSThread currentThread]);
}];

NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"____任务3___  %@",[NSThread currentThread]);
}];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

//监听操作是否完成
op3.completionBlock = ^{
    NSLog(@"op3已经完成了");
};

//添加依赖关系  注意不能循环依赖
[op1 addDependency:op3];
[op2 addDependency:op2];

[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
线程之间的通信
  __block UIImage *image1;
__block UIImage *image2;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:@""];
    NSData *data = [NSData dataWithContentsOfURL:url];
    image1 = [UIImage imageWithData:data];
    
    //回到主线程
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
       //刷新主线程
    }];
    
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:@""];
    NSData *data = [NSData dataWithContentsOfURL:url];
    image2 = [UIImage imageWithData:data];
    
    //回到主线程
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //刷新主线程
    }];
    
}];

NSBlockOperation *complete = [NSBlockOperation blockOperationWithBlock:^{
    
}];

[complete addDependency:op1];
[complete addDependency:op2];

相关文章

  • OC--各种线程锁

    参考:正确使用多线程同步锁@synchronized()iOS中的锁iOS多线程安全详解iOS 常见知识点(三):...

  • iOS多线程的一些知识点

    讲述一些有关iOS中的多线程知识点,以及一些应用实例 一、多线程基础知识 多线程是一个比较轻量级的方法来实现单个应...

  • iOS 多线程知识相关

    前言 主要是整理下关于iOS中多线程的相关知识点,加强记忆 目前iOS有四种多线程 1.Pthreads2.NST...

  • iOS多线程知识点

    最近整理的iOS多线程方面的知识点,iOS中总共有4种实现多线程的方案,但是pthread是基于C语言并且不太好用...

  • iOS多线程之pthread和NSThread

    iOS开发中,多线程相关的知识点主要包括pthread、NSThread、NSOperation和GCD,我们经常...

  • iOS多线程实现方案之 -- NSThread

    书接上回, 上次谈到iOS 多线程知识点总结之: 进程和线程, 接着就是 多线程实现方案里面的 NSThread...

  • iOS知识体系总结-多线程

    注意:更新内容会同步到GitHub iOSWiki-知识体系总结 总结-多线程 iOS知识点/操作系统 #iOS...

  • iOS 关于多线程(GCD)

    一、关于iOS多线程的一些简单操作 链接地址:多线程简介 二、iOS开发多线程篇—GCD的常见用法 主要为:延迟执...

  • iOS---多线程的一些注意点

    本文是笔者通过前辈的指导,然后总结一些 IOS 多线程的注意点,总结的知识点不会太全面,希望读者们多多谅解。本文不...

  • iOS多线程相关面试题

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

网友评论

      本文标题:iOS多线程的一些知识点

      本文链接:https://www.haomeiwen.com/subject/vwoomxtx.html