新浦京81707con > 注册购买 > 多线程详解,多线程总结

原标题:多线程详解,多线程总结

浏览次数:151 时间:2020-03-29

4.4 NSOperation和NSOperationQueue的要紧性质和艺术

NSOperation

  1. NSOperation的依赖 - addDependency:(NSOperation *)op;
// 操作op1依赖op5,即op1必须等op5执行完毕之后才会执行// 添加操作依赖,注意不能循环依赖,如果循环依赖会造成两个任务都不会执行// 也可以夸队列依赖,依赖别的队列的操作 [op1 addDependency:op5];
  1. NSOperation操作监听void (^completionBlock)
// 监听操作的完成// 当op1线程完成之后,立刻就会执行block块中的代码// block中的代码与op1不一定在一个线程中执行,但是一定在子线程中执行op1.completionBlock = ^{ NSLog(@"op1已经完成了---%@",[NSThread currentThread]); };

NSOperationQueue

  1. maxConcurrentOperationCount
 //1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; /* 默认是并发队列,如果最大并发数>1,并发 如果最大并发数==1,串行队列 系统的默认是最大并发数-1 ,表示不限制 设置成0则不会执行任何操作 */ queue.maxConcurrentOperationCount = 1;
  1. suspended
//当值为YES的时候暂停,为NO的时候是恢复queue.suspended = YES;
  1. -cancelAllOperations;
//取消所有的任务,不再执行,不可逆[queue cancelAllOperations];

小心:暂停和撤消只能暂停或打消处于等候情况的任务,不能够暂停或注销正在试行中的职分,必得等正在实施的天职实施完结之后才会暂停,假如想要暂停也许撤废正在进行的职务,能够在每一个职责之间即每当实行完一段耗时操作之后,决断是或不是职务是还是不是被吊销也许暂停。要是想要正确的垄断(monopoly卡塔尔,则必要将剖断代码放在职分之中,不过不提议如此做,频仍的决断会开销太多时间

GCD中获取串行有2种路子

使用dispatch_queue_create函数创造串行队列// 创立串行队列(队列类型传递NULL或然DISPATCH_QUEUE_SERIAL)

dispatch_queue_t queue = dispatch_queue_create("com.520it.queue",NULL);

二、多线程才具

column column
计数方案 简介
pthread 一套通用的多线程API,适用于UnixLinuxWindows等系统,跨平台可移植,使用难度大
NSTread 使用更加面向对象,简单易用,可直接操作线程对象
GCD 旨在代替NSTread等多线程技术,充分利用设备的多核
NSOperation 基于GCD(底层是GCD),比GCD多了一些更简单使用的功能,使用更加面向对象

4. 线程的串行

1个线程中任务的实施是串行的只要要在1个线程中奉行三个职分,那么只可以二个一个地按梯次试行这么些职分也便是说,在同时内,1个线程只可以进行1个职分

扩展
  • 原子和非原子属性

    • atomic:原子属性,为setter方法加锁(暗中认可正是atomic)
    • nonatomic:非原子属性,不会为setter方法加锁
    • 注意点: atomic系统自动给大家抬高的锁不是互斥锁/ 自旋锁
  • 自旋锁和互斥锁相比较

    • 共同点
      • 都能够确认保证多线程在同等时候, 只可以有一个线程操作锁定的代码
    • 不同点
      • 若果是互斥锁, 倘若现在被锁住了, 那么后边来得线程就能够跻身”休眠”状态, 直到解锁之后, 又会唤醒线程继续试行
      • 倘假设自旋锁, 倘诺未来被锁住了, 那么前面来得线程不会进来休眠状态, 会平昔傻傻的等待, 直到解锁之后立即施行
      • 自旋锁更切合做一些超短的操作

蓄势待发是Grand Central Dispatch,可译为“酷爆了的心脏调解器”纯C语言,提供了超级多强盛的函数

  • GCD的优势
  • GCD是苹果集团为多核的互相运算提议的消除方案
  • GCD会自动利用更加多的CPU内核

  • GCD会自动管理线程的生命周期(创制线程、调解职分、销毁线程)

  • 程序员只需求报告GCD想要施行怎么着职务,无需编写制定任何线程管理代码

  • GCD中有2个为主概念

  • 职分:实行如何操作
  • 队列:用来寄存义务

  • GCD的利用就2个步骤

    • 定制职务
    • 规定想做的事务
    • 将任务增添到行列中
      • GCD会自行将队列中的职务收取,放到对应的线程中推行
      • 任务的收取坚守队列的FIFO原则:先进先出,后进后出
  • 怎么试行职务

    • 同步函数dispatch_sync
    • 不辜负有开启新线程的力量
    • 异步函数dispatch_async
      • 富有开启新线程的力量
    • 联手和异步首要影响:能否拉开新的线程
    • 并发队列(Concurrent Dispatch Queue)

    • 能够让多个职分并发试行(自动开启多少个线程同时推行职责)

    • 并发功效只有在异步(dispatch_async)函数下才有效
    • 和睦成立: dispatch_queue_t queue = dispatch_queue_create("com.Mg.lym", DISPATCH_QUEUE_CONCURRENT);
    • 大局并发队列 : dispatch_get_global_queue;
###使用dispatch_queue_create函数创建队列dispatch_queue_tdispatch_queue_create(const char *label, // 队列名称 dispatch_queue_attr_t attr); // 队列的类型dispatch_queue_t queue = dispatch_queue_create("com.baidu.queue", DISPATCH_QUEUE_CONCURRENT);###GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建使用dispatch_get_global_queue函数获得全局的并发队列dispatch_queue_tdispatch_get_global_queue(dispatch_queue_priority_t priority, // 队列的优先级 unsigned long flags); // 此参数暂时无用,用0即可###获得全局并发队列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);###全局并发队列的优先级#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认#define DISPATCH_QUEUE_PRIORITY_LOW  // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台```*** >- 串行队列(Serial Dispatch Queue) - 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
主线程的最主要功效

<1>显示刷新UI界面
<2>管理UI事件(比方点击事件、滚动事件、拖拽事件等)

4.1 NSOperation的创建

NSOperation是个抽象类,并不富有封装操作的技艺,必须使用它的子类选择NSOperation子类的办法有3种

  1. NSInvocationOperation
 /* 第一个参数:目标对象 第二个参数:选择器,要调用的方法 第三个参数:方法要传递的参数 */NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector object:nil];//启动操作[op start];
  1. NSBlockOperation
//1.封装操作NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ //要执行的操作,在主线程中执行 NSLog(@"1------%@",[NSThread currentThread]); }];//2.追加操作,追加的操作在子线程中执行,可以追加多条操作[op addExecutionBlock:^{ NSLog(@"---download2--%@",[NSThread currentThread]); }];[op start];
  1. 自定义子类继承NSOperation,达成内部相应的诀窍
// 重写自定义类的main方法实现封装操作-main{ // 要执行的操作}

// 实例化一个自定义对象,并执行操作CLOperation *op = [[CLOperation alloc]init];[op start];

自定义类封装性高,复用性高。

采用主队列(跟主线程相关联的队列)

主队列是GCD自带的一种独特的串行队列放在主队列中的职务,都会安置主线程中实施使用dispatch_get_main_queue(卡塔尔取得主队列dispatch_queue_t queue = dispatch_get_main_queue();```

    • 手拉手和异步首要影响:能否敞开新的线程

    • 同盟:只是在时下线程中实践职分,不有所开启新线程的技术

    • 异步:能够在新的线程中实践职务,具有开启新线程的本领
    • 并发和串行主要影响:任务的试行办法
      • 现身:允许多少个任务并发实行
      • 串行:贰个职责实践落成后,再实行下三个职务
  • 异步 并行 = 会开启新的线程
- 异步函数, 会先执行完所有的代码, 再在子线程中执行任务
  • 异步 串行 = 会创造新的线程, 但是只会创制一个新的线程, 全部的天职都在此叁个新的线程中实行
  • 联手 并行 = 不会敞开新的线程
    • 实则就一定于一块 串行
    • 一起函数, 只要代码奉行到了一块儿函数的那一行, 就能应声推行职责, 独有任务实行达成才会持续未来施行
  • 联合 串行 = 不会创制新的线程
  • 异步 主队列 = 不展会开新的线程
    • 假假使主队列, 永恒都在主线程中实行
  • 一起 主队列 = 须求牢记的就一些: 同步函数不可能搭配主队列使用
    • 只顾: 有不相同的状态, 固然同步函数是在异步函数中调用的, 那么未有其余难题

图片 1GCD的各类组合

  • GCD线程间通讯示例
    • 使用异步函数试行职分
    • 利用主队列回到主线程更新UI
// 从子线程回到主线程dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ //执行耗时的异步操作... dispatch_async(dispatch_get_main_queue(),^{ //回到主线程,执行UI刷新操作 });});
  • GCD中的常用方法
    • 延期实践
 ### 使用NSTimer [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector userInfo:nil repeats:NO]; // 内部实现原理就是NSTimer ### 调用NSObject的方法 [self performSelector:@selector withObject:nil afterDelay:2.0]; // 将需要执行的代码, 和方法放在一起, 提高代码的阅读性 // 相比NSTimer来说, GCD的延迟执行更加准确 ### 使用GCD函数 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"%@", [NSThread currentThread]); NSLog;};### run方法-run{ NSLog(@"%s", __func__);}
  • 一遍性代码
    • 全方位程序运营进度中, 只会实施三遍
static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{ NSLog(@"明哥写的代码被执行了");});
  • 快快迭代
/* 第一个参数: 需要执行几次任务 第二个参数: 队列 第三个参数: 当前被执行到得任务的索引 /* dispatch_apply(10, dispatch_get_global_queue, ^(size_t index) { NSLog(@"%@, %zd",[NSThread currentThread] , index); });

### 通过比较for循环和apply遍历时间,看看哪个比较高效- apply{ /* 第一个参数: 需要执行几次任务 第二个参数: 队列 第三个参数: 当前被执行到得任务的索引 */ /* dispatch_apply(10, dispatch_get_global_queue, ^(size_t index) { NSLog(@"%@, %zd",[NSThread currentThread] , index); }); */ // 1.获取images文件夹中所有的文件 NSString *sourcePath = @"/Users/ming/Desktop/abc"; NSString *dest = @"/Users/ming/Desktop/lym"; // 2.获取images文件夹中所有的文件 NSFileManager *mgr = [NSFileManager defaultManager]; NSArray *subPaths = [mgr subpathsAtPath:sourcePath]; // NSLog(@"%@", subPaths); // 3.剪切文件到lym文件夹中 /* CFAbsoluteTime begin = CFAbsoluteTimeGetCurrent(); for (int i = 0; i < subPaths.count; i  ) { // 3.1获取当前遍历到得文件的名称 NSString *fileNmae = subPaths[i]; // 3.2根据当前文件的名称, 拼接全路径 NSString *fromPath = [sourcePath stringByAppendingPathComponent:fileNmae]; NSString *toPath = [dest stringByAppendingPathComponent:fileNmae]; NSLog(@"fromPath = %@", fromPath); NSLog(@"toPath = %@", toPath); [mgr moveItemAtPath:fromPath toPath:toPath error:nil]; } CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@"花费了%f秒", end -begin); */ CFAbsoluteTime begin = CFAbsoluteTimeGetCurrent(); dispatch_apply(subPaths.count, dispatch_get_global_queue, ^(size_t index) { // 3.1获取当前遍历到得文件的名称 NSString *fileNmae = subPaths[index]; // 3.2根据当前文件的名称, 拼接全路径 NSString *fromPath = [sourcePath stringByAppendingPathComponent:fileNmae]; NSString *toPath = [dest stringByAppendingPathComponent:fileNmae]; NSLog(@"fromPath = %@", fromPath); NSLog(@"toPath = %@", toPath); [mgr moveItemAtPath:fromPath toPath:toPath error:nil]; }); CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@"花费了%f秒", end -begin); // 花费了0.001280秒}
  • barrier
  • 要想实行完前边全部的义务再实践barrier必得满足八个条件
  • 富有任务都以在同两个行列中

  • 队列不可能是全局并行队列, 必得是自个儿创建的队列

  • barrier方法早前增进的天职会先被实践, 独有等barrier方法以前增进的义务推行完结, 才会举行barrier

  • 还要如果是在barrier方法之后加上的天职, 必需等barrier方法施行完毕之后才会起首施行

  • 队列组

    • 要是想落成, 等前面全部的职务都实施完成, 再实行某二个特定的职务, 那么能够因而GCD中的组来完结
    • 譬喻当前组中保有的职分都试行完结了, 那么系统会活动调用dispatch_group_notify
  • 先是:分别异步施行2个耗费时间的操作
  • 附带:等2个异步操作都执行实现后,再回到主线程试行操作
  • 假设想要急迅便捷地促成上述须要,能够思虑用队列组/栅栏函数
  • 详细完毕

4.多线程:

三个进度可以敞开多条线程,每条线程能够出现(相同的时间)实施不一致的天职;四线程能够提升程序的进行效用

3.1 任务和队列

GCD中有2个着力概念:职务和队列职责:实行什么样操作,职分有两种实行办法: 协助举行函数异步函数,他们之间的界别是一只:只好在当下线程中试行职分,不富有开启新线程的工夫,职责立刻立时施行,会阻塞当前线程并等待 Block中的任务试行实现,然后当前线程才会一而再接二连三往下运作

异步:能够在新的线程中实行职责,具有开启新线程的技巧,但不肯定会开新线程,当前线程会一贯往下进行,不会梗塞当前线程

队列:用来存放在任务,分为串行队列并行队列串行队列(Serial Dispatch Queue)让职务四个随着一个地推行(多少个职责试行实现后,再奉行下贰个任务)并发队列(Concurrent Dispatch Queue)可以让四个职务并发实践(自动开启多个线程同时举办义务)并发成效独有在异步(dispatch_async)函数下才使得

GCD的行使就2个步骤

  1. 定制职分鲜明想做的业务

  2. 将任务加多到行列中GCD会自动将队列中的义务抽出,放到对应的线程中执行职分的抽出信守队列的FIFO原则:先进先出,后进后出

  • 十六线程的帮助和益处1.能正好升高程序的实施功效2.能确切巩固财富利用率(CPU、内部存款和储蓄器利用率)

  • 三十二线程的缺点1.创制线程是有付出的,iOS下首要资本包罗:内核数据布局、栈空间(子线程512KB、主线程1MB,也能够动用-setStackSize:设置,但必需是4K的翻番,何况最小是16K),创制线程差不离须要90飞秒的创建时间2.假若翻开一大波的线程,会裁减程序的性质3.线程越多,CPU在调节线程上的耗费就越大4.主次设计尤为目迷五色:比如线程之间的通讯、多线程的数目分享

一、进度与线程

2. NSThread的使用

iOS中二十四线程的贯彻方案

| 应用方案 | 简要介绍 | 语言 | 线程生命周期 | 使用频率 || -------- | -----: | :----: | | :----: | | :----: || 1.pthread | 1.一套通用的十六线程API。 2.适用于UnixLinuxWindows等系统。 3.跨平台可移植。 4.采取难度大 | C | 技师管理 | 大概不用 || 2.NSThread | 1.施用进一层面向对象 。 2.简便易用,可一贯操作线程对象 | OC | 程序猿管理 | 临时使用 || 3.GCD |1.意在代表NSThread等线程本领。2.丰富利用设备的多核 | C | 自动管理 | 通常应用 || 4.NSOperation | 1.基于GCD。2.比GCD多了一部分更简便实用的功力。3.使用更为面向对象 | OC | 自动管理 | 平时使用 |

图片 2iOS中二十四线程的兑现方案

  • 创建pthread
    • pthread_create
  • 若果create贰回就能够创制一个新的线程
  • 系统会自行在子线程中调用传入的函数
/*第一个参数: 线程的代号第二个参数: 线程的属性第三个参数: 指向函数的指针, 就是将来线程需要执行的方法第四个参数: 给第三个参数的指向函数的指针 传递的参数void *(*functionP)void * == id一般情况下C语言中的类型都是以 _t或者Ref结尾*/pthread_t threadId;// 只要create一次就会创建一个新的线程pthread_create(&threadId , NULL, &demo, "lym");
  • 八个NSThread对象就象征一条线程
  • 三种创立形式
  • 第一种
    • alloc init
    • 在乎: 须求手动运营线程
    • 特征: 系统里头会retain当前线程
    • 独有线程中的方法实行完结, 系统才会将其出狱
// 第一种创建方式NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector object:nil];[thread start];// 线程一启动,就会在线程thread中执行self的run方法
  • 第二种
    • 不用手动调用start方法, 系统会活动运转
    • 不曾重回值, 无法对线程进行越多的装置
    • 使用项景: 必要快捷便捷的奉行线程
// 第二种创建方式// 创建线程后自动启动线程[NSThread detachNewThreadSelector:@selector toTarget:self withObject:nil];// 系统就会自动创建一个子线程, 并且在子线程中自动执行self的@selector方法(隐式创建并启动线程)[self performSelectorInBackground:@selector withObject:nil];/**上述2种创建线程方式的优缺点优点:简单快捷缺点:无法对线程进行更详细的设置*/
  • 垄断(monopoly卡塔尔国线程状态

    • 创办出来 -> 新建状态
    • 调用start -> 准备稳当
    • 被CPU调用 -> 运行
    • sleep -> 阻塞
    • 实行完结, 或然被胁持关闭 -> 一命归阴

      • 专心: 假如强逼关闭线程, 关闭之后的别样操作都不能实践

        图片 3线程状态

// 启动线程//进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态-start;阻塞线程//进入阻塞状态 sleepUntilDate:date; sleepForTimeInterval:(NSTimeInterval)time;强制停止线程//进入死亡状态 exit;###warm 注意:一旦线程停止了,就不能再次开启任务```- 主线程相关用法

(NSThread*卡塔尔mainThread; // 获得主线程-isMainThread; // 是还是不是为主线程 isMainThread; // 是或不是为主线程NSThread *current = [NSThread currentThread]; // 取安妥前线程-setName:(NSString *卡塔尔name;// setter线程的名字-(NSString *卡塔尔name; // getter线程的名字```

    • 财富共享

      • 块财富大概会被多少个线程共享,也便是三个线程大概会访谈同一块财富
      • 举个例子多个线程访谈同多个指标、同二个变量、同叁个文本
      • 当八个线程访问同一块资源时,超轻巧吸引多少错乱和数据安全难题

        图片 4存取钱图片 5卖票定票

  • 安全隐患解决– 互斥锁

    • 互斥锁使用格式
@synchronized{ // 需要锁定的代码 }注意:锁定1份代码只用1把锁,用多把锁是无效的``` - 互斥锁的优缺点 >- 优点:能有效防止因多线程抢夺资源造成的数据安全问题 - 缺点:需要消耗大量的CPU资源 - 互斥锁的使用前提:多条线程抢夺同一块资源 - 相关专业术语:线程同步 >- 线程同步的意思是:多条线程在同一条线上执行 - 互斥锁,就是使用了线程同步技术- ####NSThread线程间通信 - 什么叫做线程间通信 - 在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 - 线程间通信的体现 - 1个线程传递数据给另1个线程 - 在1个线程中执行完特定任务后,转到另1个线程继续执行任务 - 线程间通信常用方法

-performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait;-performSelector:aSelector onThread:(NSThread *)thread withObject:arg waitUntilDone:wait;```

图片 6图片下载

performSelectorOnMainThread方法中waitUntilDone:NO参数的含义如果传入的是YES: 那么会等到主线程中的方法执行完毕, 才会继续执行下面其他行的代码如果传入的是NO: 那么不用等到主线程中的方法执行完毕, 就可以继续执行下面其他行的代码注意点: 更新UI一定要在主线程中更新[self performSelectorInBackground:@selector(download2:) withObject:url];[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];

1.进程:

系统中正在运作的一个应用程序,每一种进度之间是单身的,各样进程均运转在其专项使用且受有限扶助的内部存款和储蓄器空间内

3. GCD的使用

GCD的全称是Grand Central Dispatch,是纯C语言,提供了丰硕多强盛的函数

GCD的优势GCD是苹果公司为多核的相互运算建议的建设方案GCD会活动利用更加多的CPU内核GCD会活动管理线程的生命周期(创立线程、调整职责、销毁线程)程序猿只供给报告GCD想要实践什么样义务,无需编写制定任何线程管理代码

使用group实现
- group{ // GCD组 // 1.创建队列 dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_CONCURRENT); // 创建一个组 dispatch_group_t group = dispatch_group_create(); // 2.添加一个下载图片任务 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://stimgcn1.s-msn.com/msnportal/ent/2015/08/04/7a59dbe7-3c18-4fae-bb56-305dab5e6951.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; NSLog(@"下载图片1 %@", [NSThread currentThread]); }); // 3.再添加一个下载图片任务 dispatch_group_async(group, queue, ^{ NSURL *url = [NSURL URLWithString:@"http://y1.ifengimg.com/cmpp/2015/08/05/04/15495f65-5cd2-44cd-a704-bc455d629fe3_size25_w510_h339.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; NSLog(@"下载图片2 %@", [NSThread currentThread]); }); dispatch_group_notify(group, queue, ^{ NSLog(@"合成图片 %@", [NSThread currentThread]); // 1.创建图片上下文 UIGraphicsBeginImageContext(CGSizeMake); // 2.绘制第一张图片 [self.image1 drawInRect:CGRectMake(0, 0, 100, 200)]; // 3.绘制第二张图片 [self.image2 drawInRect:CGRectMake(100, 0, 100, 200)]; // 4.从上下文中取出图片 UIImage *res = UIGraphicsGetImageFromCurrentImageContext(); // 5.关闭上下文 UIGraphicsEndImageContext(); // 6.回到主线程更新UI dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"更新UI %@", [NSThread currentThread]); self.imageView.image = res; }); });}

2.线程:

1个经过要想举行职分,必需得有线程(每四个进度最少要有一条线程);线程是经过的主干进行单元,三个经过(程序)的持有义务都在线程中举办
1个线程中奉行职分是串行的,同不常候只好试行叁个职分,顺序试行全数职分;

4. NSOperation的使用

NSOperation 是苹果公司对 GCD 的卷入,完周全向对象,并比GCD多了有个别更简单实用的成效,所以采纳起来更为便利易于驾驭。NSOperation 和NSOperationQueue 分别对应 GCD 的 职分 和 队列。

NSOperation和NSOperationQueue实现二十四线程的具体步骤1.将索要举行的操作封装到二个NSOperation对象中2.将NSOperation对象增添到NSOperationQueue中系统会自动将NSOperationQueue中的NSOperation抽出来,并将抽出的NSOperation封装的操作放到一条新线程中实践

四线程在iOS开拓中的应用

    • 二个iOS程序运营后,暗许会开启1条线程,称为“主线程”或“UI线程”
  • 主线程

    • 显示/刷新UI界面
    • 拍卖UI事件(譬如点击事件、滚动事件、拖拽事件等)
  • 主线程的应用注意

    • 别将比较耗费时间的操作放到主线程中
    • 耗费时间操作会卡住主线程,严重影响UI的流畅度,给客商一种“卡”的坏体验

      图片 7耗费时间操作会卡住主线程

5.NSOperation

<1>NSOperation的作用
1.相配使用NSOperation和NSOperationQueue也能兑现八线程编制程序

2.NSOperation和NSOperationQueue完成四线程的具体步骤

  • 先将索要奉行的操作封装到一个NSOperation对象中
  • 下一场将NSOperation对象增加到NSOperationQueue中
  • 系统会自动将NSOperationQueue中的NSOperation抽出来
  • 将抽出的NSOperation封装的操作放到一条新线程中实施

3.NSOperation是个抽象类,并不有所封装操作的手艺,必须使用它的子类

4.接受NSOperation子类的措施有3种

  • NSInvocationOperation
  • NSBlockOperation
  • 自定义子类世襲NSOperation,完成内部相应的形式

5.创建NSInvocationOperation对象

-(id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
  • 调用start方法起头执行操作
 -(void)start;

假诺推行操作,就能调用target的sel方法

注意:

  • 暗中认可情形下,调用了start方法后并不会开一条新线程去实践操作,而是在这里时此刻线程同步试行操作
  • 除非将NSOperation放到多个NSOperationQueue中,才会异步实行操作

6.创建NSBlockOperation对象

 (id)blockOperationWithBlock:(void (^)(void))block;
  • 经过addExecutionBlock:方法加多更加多的操作
-(void)addExecutionBlock:(void (^)(void))block;
  • 注意:只要NSBlockOperation封装的操作数 > 1,就能够异步实行操作

<2>NSOperationQueue的作用
1.NSOperation能够调用start方法来推行职务,但默许是叁只施行的
2.如若将NSOperation增多到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作

  • 加上操作到NSOperationQueue中
-(void); addOperation:(NSOperation *)op
-(void)addOperationWithBlock:(void (^)(void))block;

<3>什么是并发数
1.并且实施的天职位数量
2.比方,同不常候开3个线程实施3个任务,并发数正是3

  • 最大并发数的有关办法
-(NSInteger)maxConcurrentOperationCount;
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;

<4>队列的撤除、暂停、苏醒
1.撤回队列的享有操作

-(void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作

2.一曝十寒和回复队列

-(void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
-(BOOL)isSuspended;

<5>操作优先级
1.装置NSOperation在queue中的优先级,能够校订操作的施行优先级

-(NSOperationQueuePriority)queuePriority;
-(void)setQueuePriority:(NSOperationQueuePriority)p;

2.优先级的取值

NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8

<6>操作的监听
可以监听三个操作的执行实现

-(void (^)(void))completionBlock;
-(void)setCompletionBlock:(void (^)(void))block;

<7>操作依赖
1.NSOperation里边能够设置信赖来担保试行顺序

  • 举例一定要让操作A推行完后,工夫实践操作B,能够那样写
[operationB addDependency:operationA]; // 操作B依赖于操作A

2.足以在区别queue的NSOperation之间创设信任关系
3.注意:不可能互信

  • 比如A依赖B,B依赖A

<8>自定义NSOperation
1.自定义NSOperation的步子相当粗略

  • 重写- (void卡塔尔国main方法,在个中完结想进行的职务

2.重写- (void)main方法的注目点

  • 慈详创立机关释放池(因为假使是异步操作,无法访问主线程的机动释放池)
  • 一再通过- (BOOL卡塔尔(قطر‎isCancelled方法检查实验操作是不是被撤回,对裁撤做出响应

3. 历程和线程的相比较

1.线程是CPU调用的纤维单位。2.历程是CPU分配财富的矮小单位。3.叁个进程中最少要有三个线程。4.同一个进度内的线程分享进度的财富。

栅栏函数落成
- barrier{ // 如果所有的任务都在"同一个"队列中 // 那么在barrier方法之前添加的任务会先被执行, 只有等barrier方法之前添加的任务执行完毕, 才会执行barrier // 而且如果是在barrier方法之后添加的任务, 必须等barrier方法执行完毕之后才会开始执行 // 1.创建队列 dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_CONCURRENT);// dispatch_queue_t queue = dispatch_get_global_queue; // 2.添加一个下载图片任务 dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://stimgcn1.s-msn.com/msnportal/ent/2015/08/04/7a59dbe7-3c18-4fae-bb56-305dab5e6951.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image1 = [UIImage imageWithData:data]; NSLog(@"下载图片1 %@", [NSThread currentThread]); }); // 3.再添加一个下载图片任务 dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://y1.ifengimg.com/cmpp/2015/08/05/04/15495f65-5cd2-44cd-a704-bc455d629fe3_size25_w510_h339.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; self.image2 = [UIImage imageWithData:data]; NSLog(@"下载图片2 %@", [NSThread currentThread]); }); // 要想执行完前面所有的任务再执行barrier必须满足两个条件 // 1. 所有任务都是在同一个队列中 // 2. 队列不能是全局并行队列, 必须是自己创建的队列 dispatch_barrier_async(queue, ^{ NSLog(@"合成图片 %@", [NSThread currentThread]); // 1.创建图片上下文 UIGraphicsBeginImageContext(CGSizeMake); // 2.绘制第一张图片 [self.image1 drawInRect:CGRectMake(0, 0, 100, 200)]; // 3.绘制第二张图片 [self.image2 drawInRect:CGRectMake(100, 0, 100, 200)]; // 4.从上下文中取出图片 UIImage *res = UIGraphicsGetImageFromCurrentImageContext(); // 5.关闭上下文 UIGraphicsEndImageContext(); // 6.回到主线程更新UI dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"更新UI %@", [NSThread currentThread]); self.imageView.image = res; }); });}
  • NSOperation的作用
    • 匹配使用NSOperation和NSOperationQueue也能促成十二线程编制程序
  • NSOperation和NSOperationQueue达成三十二线程的具体步骤:
    • 1.先将要求实施的操作封装到一个NSOperation对象中
    • 2.然后将NSOperation对象加多到NSOperationQueue中
    • 3.体系会自动将NSOperationQueue中的NSOperation取出来
    • 4.将抽取的NSOperation封装的操作放到一条新线程中实施
  • NSOperation是个抽象类,并不辜负有封装操作的力量,必须接纳它的子类

  • 接收NSOperation子类的格局有3种

    • NSInvocationOperation
    • NSBlockOperation
    • 自定义子类继承NSOperation,完结内部相应的办法
  • 创建NSInvocationOperation对象- initWithTarget:target selector:sel object:arg;

  • 调用start方法开首实践操作- start;

    • 假诺实施操作,就能够调用target的sel方法
  • 注意

    • 默许情状下,调用了start方法后并不会开一条新线程去施行操作,而是在时下线程同步实行操作
    • 只有将NSOperation放到一个NSOperationQueue中,才会异步试行操作
  • 创建NSBlockOperation对象 blockOperationWithBlock:block;

  • 因此addExecutionBlock:方法增多更加的多的操作- addExecutionBlock:block;

  • 静心:只要NSBlockOperation封装的操作数 >1,就能够异步实行操作

  • NSOperationQueue的作用

    • NSOperation能够调用start方法来执行职分,但暗许是同步实行的
    • 借使将NSOperation增添到NSOperationQueue中,系统会活动异步实施NSOperation中的操作
  • 拉长操作到NSOperationQueue中

-addOperation:(NSOperation *)op;-addOperationWithBlock:block;
  • 怎么着是并发数

    • 还要实行的天职位数量
    • 诸如,同偶然间开3个线程实施3个职责,并发数就是3
  • 最大并发数的有关办法

-(NSInteger)maxConcurrentOperationCount;-setMaxConcurrentOperationCount:(NSInteger)cnt;
  • 撤回队列的具备操作
-cancelAllOperations;提示:也可以调用NSOperation的- cancel方法取消单个操作
  • 暂停和还原队列
-setSuspended:b;// YES代表暂停队列,NO代表恢复队列-isSuspended;
  • 操作注重

    • NSOperation之间能够设置重视来确认保证实行顺序

      • 举个例子必须求让操作A奉行完后,才干实行操作B,能够如此写[operationB addDependency:operationA]; // 操作B依赖于操作A
    • 能够在区别queue的NSOperation之间创设信任关系

      图片 8操作依赖

  • 操作的监听

    • 能够监听七个操作的施行完成
-completionBlock;-setCompletionBlock: block;
  • 自定义NSOperation

    • 自定义NSOperation的步调很简短

      • 重写- main措施,在在那之中完毕想进行的天职
    • 重写-main方法的小心点

      • 友好成立机关释放池(因为一旦是异步操作,不可能访问主线程的全自动释放池)
      • 时常通过- isCancelled措施行检查测操作是不是被吊销,对撤废做出响应
//// ViewController.m// 了解-NSOperation基本使用//// Created by ming on 16/6/6.// Copyright  2015年 ming. All rights reserved.//#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- touchesBegan:touches withEvent:(UIEvent *)event{ NSLog(@"%s", __func__); //1. 封装任务 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ // 主线程 NSLog(@"1---%@", [NSThread currentThread]); }]; // 2.追加其它任务 // 注意: 在没有队列的情况下, 如果给BlockOperation追加其它任务, 那么其它任务会在子线程中执行 [op1 addExecutionBlock:^{ NSLog(@"2---%@", [NSThread currentThread]); }]; [op1 addExecutionBlock:^{ NSLog(@"3---%@", [NSThread currentThread]); }]; // 3.启动任务 [op1 start];}- invocation{ // 注意: 父类不具备封装操作的能力 // NSOperation *op = [[NSOperation alloc] init]; // 1.封装任务 NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector object:nil]; // 2.要想执行任务必须调用start [op1 start]; NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector object:nil]; [op2 start];}- run{ NSLog(@"%@", [NSThread currentThread]);}- run2{ NSLog(@"%@", [NSThread currentThread]);}@end

//// ViewController.m// NSOpreatinoQueue的其它常用方法//// Created by apple on 16/6/6.// Copyright  2016年 Ming. All rights reserved.//#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- touchesBegan:touches withEvent:(UIEvent *)event{ // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSOperationQueue *queue2 = [[NSOperationQueue alloc] init]; // 2.创建任务 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1-------%@", [NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2-------%@", [NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"3-------%@", [NSThread currentThread]); }]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"4-------%@", [NSThread currentThread]); for (int i = 0; i < 1000; i  ) { NSLog; } }]; NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"5-------%@", [NSThread currentThread]); }]; // 3.添加依赖 [op5 addDependency:op1]; [op5 addDependency:op2]; [op5 addDependency:op3]; [op5 addDependency:op4]; // 4.监听op4什么时候执行完毕 op4.completionBlock = ^{ NSLog(@"op4中所有的操作都执行完毕了"); }; // 4.添加任务到队列 [queue addOperation:op1]; [queue addOperation:op2]; [queue2 addOperation:op3]; [queue2 addOperation:op4]; [queue addOperation:op5]; /*// dispatch_queue_t queue = dispatch_get_global_queue; dispatch_queue_t queue = dispatch_queue_create("com.ming.lym", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t queue2 = dispatch_queue_create("com.ming.lbj", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@"1-------%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2-------%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3-------%@", [NSThread currentThread]); }); dispatch_barrier_async(queue2, ^{ NSLog(@"4-------%@", [NSThread currentThread]); }); */ /* dispatch_group_t group = dispatch_group_create(); dispatch_group_t group2 = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_CONCURRENT); dispatch_group_async(group, queue, ^{ NSLog(@"1-------%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"2-------%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"3-------%@", [NSThread currentThread]); }); dispatch_group_notify(group2, queue, ^{ NSLog(@"4-------%@", [NSThread currentThread]); }); */ }@end
  • 自定义NSOperation下载图片思路– 无沙盒缓存

    图片 9NSOperation下载-无沙盒缓存

  • 自定义NSOperation下载图片思路– 有沙盒缓存

图片 10NSOperation下载-有沙盒缓存

主线程的使用注意

<1>别将相比耗时的操作放到主线程中
<2>耗费时间操作会卡住主线程,严重影响UI的通畅度,给客户一种“卡”的坏体验

2.5 NSThread线程之间的通讯

怎样叫做线程间通讯在1个经过中,线程往往不是孤立存在的,多少个线程之间必要日常开展通讯,比方大家在子线程完结下载图片后,回到主线程刷新UI彰显图片线程间通讯的反映1个线程传递数据给另1个线程在1个线程中实行完特定义务后,转到另1个线程继续实践任务

线程间通讯常用的办法

// 返回主线程- performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait;// 返回指定线程- performSelector:aSelector onThread:(NSThread *)thr withObject:arg waitUntilDone:wait;

下边大家透过三个实例看一下线程之间的通讯

#import "ViewController.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController-touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [NSThread detachNewThreadSelector:@selector(donwLoadImage) toTarget:self withObject:nil];}-donwLoadImage{ // 获取图片url地址 http://www.itunes123.com/uploadfile/2016/0421/20160421014340186.jpg NSURL *url = [NSURL URLWithString:@"http://www.itunes123.com/uploadfile/2016/0421/20160421014340186.jpg"]; // 下载图片二进制文件 NSData *data = [NSData dataWithContentsOfURL:url]; // 将图片二进制文件转化为image; UIImage *image = [UIImage imageWithData:data]; // 参数 waitUntilDone 是否等@selector(showImage:) 执行完毕以后再执行下面的操作 YES :等 NO:不等 // 返回主线程显示图片 // [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES]; // self.imageView 也可以直接调用这个方法 直接选择 setImage方法,传入参数image即可 // [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; // 返回特定的线程,[NSThread mainThread] 获得主线程 [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];}-showImage:(UIImage *)image{ self.imageView.image = image;}@end
    • 进程是指在系统中正在运作的贰个应用程序

    • 每种进度之间是单独的,种种进程均运行在其专项使用且受保险的内部存款和储蓄器空间内

    • 诸就像偶然间张开酷狗、Xcode,系统就能够分别运转2个进度

      图片 11启动2个进程

    • 1个经过要想进行职责,必得得有线程(每1个进程最少要有1条线程)
    • 三个进程的具有职分都在线程中施行
    • 1个经过中得以敞开多条线程,多条线程能够并行实施分裂的天职
    • 多线程手艺能够巩固程序的实施效用
    • eg: 进度-->车间,线程 -->车间工人(--> 是 “也正是” “比作”的情致)
三十三线程原理:

同时,CPU只好管理1条线程,独有1条线程在办事(实行);多线程并发(同期)实践,其实是CPU神速地在多条线程之间调节(切换)假如CPU调整线程的时日足够快,就诱致了多线程并发实施的假象

5. 多线程

1个经过中得以敞开多条线程,每条线程能够并行实施分裂的天职四十十二线程才具能够加强程序的实践功能

2.多线程的克拉玛依主题材料

<1>能源分享
1块能源恐怕会被多少个线程分享,也正是七个线程恐怕会访问同一块资源
譬喻说多个线程访谈同叁个对象、同贰个变量、同三个文书

当三个线程访问同一块能源时,超级轻松吸引多少错乱和数量安全难题

<2>安全祸患消除
1.排挤锁使用格式
@synchronized(锁对象卡塔尔(قطر‎ { // 须要锁定的代码 }
小心:锁定1份代码只用1把锁,用多把锁是对事情没有什么益处的

互斥锁的得失
亮点:能管用防止因四线程抢夺能源产生的多少安全主题素材
劣势:须求花销多量的CPU能源

互斥锁的采用前提:多条线程抢夺同一块能源

有关职业术语:线程同步
线程同步的乐趣是:多条线程按梯次地履行职务
互斥锁,便是运用了线程同步技巧

2.atomic和nonatomic
<1>OC在概念属性时有nonatomic和atomic二种采纳
自旋锁:
atomic:原子属性,为setter方法加锁(暗中认可正是atomic)
nonatomic:非原子属性,不会为setter方法加锁

<2>nonatomic和atomic对比
atomic:线程安全,供给花费大批量的能源
nonatomic:非线程安全,切合内部存款和储蓄器小的运动器材

<3>自旋锁与互斥锁的争论:
互斥锁:@synchronized(){}
自旋锁:atomic修饰的特性,set方法中会加多自旋锁
协作点:当八个线程访谈同三个财富的时候,通过加锁可以幸免数据安全主题材料。
不相同点:互斥锁,其余线程(除了当前正值访问数据的此外想要访问那一个数量的线程卡塔尔会处于窒碍状态(有二个再回来就绪状态的长河);自旋锁,别的线程处于非常循环的进程(不会有气象的变动)

<4>iOS开拓的建议
装有属性都宣称为nonatomic
尽量制止十六线程抢夺同一块财富
尽量将加锁、财富掠夺的业务逻辑交给劳务器端管理,减小活动顾客端的压力

本文由新浦京81707con发布于注册购买,转载请注明出处:多线程详解,多线程总结

关键词: 新浦京81707con 多线程 ios 详解 详细

上一篇:CoreText基础概念,基本用法

下一篇:没有了