iOS_多线程(二)

1.串行队列
GCD中获得串行有2种途径
(1)使用dispatch_queue_create函数创建串行队列
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
示例:
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags);
示例:
七、案例分析
案例1:使用GCD模拟售票线程。
#import "ViewController.h" @interface ViewController ()
{
NSInteger _tickets;
}
@property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
_tickets = ;
self.textView.text = @"";
self.textView.layoutManager.allowsNonContiguousLayout = NO; //用GCD创建售票线程
/**
* 队列的名称:队列的标识符
队列的方式:
DISPATCH_QUEUE_SERIAL 串行
DISPATCH_QUEUE_CONCURRENT 并行
*/
//1.创建自定义队列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
//2.往队列中添加任务
dispatch_async(queue, ^{
[self gcdSaleMethod:@"售票GCD-1"];
});
dispatch_async(queue, ^{
[self gcdSaleMethod:@"售票GCD-2"];
});
//如果采用同步方式,会将所有线程添加到主线程。
}
-(void)appendTextView:(NSString *)text
{
//获取现有的内容
NSMutableString *string = [NSMutableString stringWithString:self.textView.text];
NSRange range = NSMakeRange(string.length, );
//设置TextView
[string appendString:[NSString stringWithFormat:@"%@\n",text]];
[self.textView setText:string];
//滚动视图
[self.textView scrollRangeToVisible:range];
}
-(void)gcdSaleMethod:(NSString *)name
{
while (YES)
{
if (_tickets > )
{
//在主队列都是串行执行的
dispatch_async(dispatch_get_main_queue(), ^{
NSString *info = [NSString stringWithFormat:@"当前票数:%ld,当前线程:%@",_tickets,name];
[self appendTextView:info];
_tickets--; }); if ([name isEqualToString:@"售票GCD-1"])
{
[NSThread sleepForTimeInterval:0.3f];
}
else
{
[NSThread sleepForTimeInterval:0.2f];
}
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
NSString *info = [NSString stringWithFormat:@"已无剩余票数,当前线程:%@",name];
[self appendTextView:info];
});
break;
}
}
} @end
接下来对代码中深蓝色部分进行分析:
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
这是GCD中的一个用来执行任务的函数实质:把右边的参数(任务)提交给左边的参数(队列)进行执行。采用的是异步的方式。
案例2:使用GCD模拟售票线程,与案例1稍有不同,案例2中使用了线程组。
#import "ViewController.h" @interface ViewController ()
{
NSInteger _tickets;
}
@property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
_tickets = ;
self.textView.text = @"";
self.textView.layoutManager.allowsNonContiguousLayout = NO; //用GCD创建售票线程 /**
* 队列的名称:队列的标识符
队列的方式:
DISPATCH_QUEUE_SERIAL 串行
DISPATCH_QUEUE_CONCURRENT 并行
*/
//1.自定义队列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
//创建线程组
dispatch_group_t group = dispatch_group_create();
//2.创建线程组往队列中添加任务
dispatch_group_async(group, queue, ^{
[self gcdSaleMethod:@"售票GCD-1"];
});
//调度群组异步任务
dispatch_group_async(group, queue, ^{
[self gcdSaleMethod:@"售票GCD-2"];
}); //等线程组中的所有任务完成后,会接收到通知
dispatch_group_notify(group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self appendTextView:@"已无剩余票啦!"];
});
});
}
-(void)appendTextView:(NSString *)text
{
NSMutableString *string = [NSMutableString stringWithString:self.textView.text];
NSRange range = NSMakeRange(string.length, ); [string appendString:[NSString stringWithFormat:@"%@\n",text]];
[self.textView setText:string]; [self.textView scrollRangeToVisible:range];
}
-(void)gcdSaleMethod:(NSString *)name
{
while (YES)
{
if (_tickets > )
{
//在主队列都是串行执行的
dispatch_async(dispatch_get_main_queue(), ^{
NSString *info = [NSString stringWithFormat:@"当前票数:%ld,当前线程:%@",_tickets,name];
[self appendTextView:info];
_tickets--;
});
if ([name isEqualToString:@"售票GCD-1"])
{
[NSThread sleepForTimeInterval:0.3f];
}
else
{
[NSThread sleepForTimeInterval:0.2f];
}
}
else
{
break;
}
}
}
@end
以上两个案例,实现的都是模拟售票,运行结果如下图:

八、延时任务的执行
在软件开发过程中,偶尔会出现,不希望某个线程立马执行,而是在经过一段时间之后再去调度执行,这就会出现任务的延时调度问题。接下来通过3种方法来实现任务的延时执行,在执行3秒之后再输出@“hello world”。
方式1:使用NSObject的方法
- (void)viewDidLoad {
[super viewDidLoad];
// 延迟执行
//1.NSObject中的方式
[self performSelector:@selector(printString:) withObject:@"hello world" afterDelay:3.0];
}
-(void)printString:(NSString *)str
{
NSLog(@"%@",str);
}
方式2:使用GCD的方式
- (void)viewDidLoad {
[super viewDidLoad];
//2.GCD中的方法
/**
参数解析
1.基准时间:程序运行时的时间
2.偏移时间(单位:纳秒)以当前运行时间为基准在多久之后进行执行
*/
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, 3.0*NSEC_PER_SEC);
//将准备输出的字符串添加到队列中去,采用延迟的方式进行等待执行输出
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
[self printString:@"hello world"];
});
}
-(void)printString:(NSString *)str
{
NSLog(@"%@",str);
}
方式3:使用NSTimer定时器的方式(此处给大家分享使用定时器实现延时任务执行的两种方式)
- (void)viewDidLoad {
[super viewDidLoad];
//使用定时器
//第一种
self.timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(printString) userInfo:nil repeats:YES];
[self.timer fire];
}
-(void)printString
{
NSLog(@"hello world");
}
- (void)viewDidLoad {
[super viewDidLoad];
//使用定时器
//第二种
self.timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(printString:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
-(void)printString
{
NSLog(@"hello world");
}
在以上两段代码中,有两处蓝色标明的部分,参数repeats,它的作用是:如果参数值为YES,每隔3秒就会输出“hello world”一次。如果参数值为NO,仅输出一次。现在知道了,当repeats的参数值为YES时,会一直执行下去,但又该怎样将它结束掉呢?在NSTimer中给出了停止的方法,看以下代码。
//停止定时器
[self.timer invalidate];
九、仅一次任务执行、多次重复任务执行
在ios中,给出了仅一次任务执行、多次重复任务执行的方法。废话不多说,直接看代码。
案例1:仅一次任务执行的方法
//dispatch_once()函数执行时需要传入一个dispatch_once_t类型(本质就是long型整数)的指针(即predicate参数),该指针用于变量用于判断代码块是否已经执行过。
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
NSLog(@"====执行代码块===");
[NSThread sleepForTimeInterval:3.0];
});
案例2:多次重复任务执行的方法
//dispatch_apply()函数将控制提交的代码块重复执行多次,如果该代码块被提交给并发队列,系统可以使用多个线程并发执行同一个代码块。
//控制代码块执行5次
dispatch_apply(, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^(size_t time) {
//time形参代表当前正在执行第几次
NSLog(@"===执行【%lu】次===%@",time,[NSThread currentThread]);
});
经过两天的学习,多线程也告一段落了,现在来总结一下。首先先来看:NSThread、NSOperation、GCD三种多线程技术的流程对比

iOS_多线程(二)的更多相关文章
- IOS_多线程_ASI_AFN_UIWebView
H:/0730/00_多线程4票种_ViewController.h // // ViewController.h // 卖票 // // Created by apple on 13-7-29. / ...
- java 多线程二
java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...
- java基础-多线程二
java基础-多线程二 继承thread和实现Runnable的多线程每次都需要经历创建和销毁的过程,频繁的创建和销毁大大影响效率,线程池的诞生就可以很好的解决这一个问题,线程池可以充分的利用线程进行 ...
- C#夯实基础之多线程二:主线程、前台线程与后台线程
我们在<C#夯实基础之多线程一:初识多线程>一文中第二部分中指出,既然windows最终发展出了多线程模型,按理说,我们直接使用一个.NetFramework的线程类就可以直接撸代码了,但 ...
- Java:多线程<二> 同步
由于多线程的访问出现延迟和线程的随机性,在使用多线程时往往会伴随安全性的问题,这些问题一旦出现将会是非常严重的.为了解决这种安全性问题,synchronized出现了. synchronized用法一 ...
- Java多线程——<二>将任务交给线程,线程声明及启动
一.任务和线程 <thinking in java>中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的. 正如前文所提到的,任务只是一段代码,一段要达成 ...
- 从零开始学习Java多线程(二)
前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处 ...
- 多线程二:线程池(ThreadPool)
在上一篇中我们讲解了多线程的一些基本概念,并举了一些例子,在本章中我们将会讲解线程池:ThreadPool. 在开始讲解ThreadPool之前,我们先用下面的例子来回顾一下以前讲过的Thread. ...
- IOS_多线程
苹果的Cocoa框架支持的多线程机制有三中NSThread.GCD.NSOperation. NSThread:是官方推荐的也是最主要的线程创建方式,可是须要开发这自己去管理线程的生命周期比如线程同步 ...
随机推荐
- 微信小程序 模块化
模块化也就是将一些通用的东西抽出来放到一个文件中,通过module.exports去暴露接口.我们在最初新建项目时就有个util.js文件就是被模块化处理时间的 /** * 处理具体业务逻辑 */ f ...
- ssh 面试
Struts1工作原理1. 初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总 控制器会读取配置文件(st ...
- MEF基础概念学习笔记
MEF,是微软.net框架下的一个框架类库.可以使你的程序低耦合的加载扩展.在开发插件,或者开发一些需要灵活扩展的功能的时候经常用到.例如微软给出的计算器的例子.当你开发计算器的时候,初始功能只提供了 ...
- poj 2513(欧拉路径+字典树映射)
题目链接:http://poj.org/problem?id=2513 思路:题目还是很简单的,就是判断是否存在欧拉路径,我们给每个单词的头和尾映射序号,统计度数.对于给定的无向图,当且仅当图连通并且 ...
- 《从零开始学Swift》学习笔记(Day 36)——静态方法
原创文章,欢迎转载.转载请注明:关东升的博客 静态方法与静态属性类似,Swift中定义了静态方法,也称为类型方法.静态方法的定义与静态属性类似,枚举和结构体的静态方法使用的关键字是static:类静态 ...
- 【穿插】Python基础之文件、文件夹的创建,对上一期代码进行优化
在上一期妹子图的爬虫教程中,我们将图片都保存在了代码当前目录下,这样并不便于浏览,我们应该将同一个模特的图片都放在一个文件夹中. 今天我们就简单讲一下Python下如何创建文件.文件夹,今后就可以用上 ...
- Mybatis Insert 返回主键ID
<insert id="insert" useGeneratedKeys="true" keyProperty="u_Id" para ...
- Spring 缓存注解@Cacheable 在缓存时候 ,出现了第一次进入调用 方法 ,第二次不调用的异常
代码: @Override @Cacheable(value = CACHE_NAME, key = "'CartItemkey_'+#uId") public List<S ...
- TFS二次开发-基线文件管理器(5)-源码文件的读取
在上一节中,我们在保存标签之前,已经将勾选的文件路径保存到了Listbox中,这里只需要将保存的数据输出去为txt文档就可以做版本控制了. 版本文件比较复杂的是如何读取,也就是如何通过文件路径 ...
- MySql最左前缀原则
简单整理记录下,之前一直都没有关注过这个问题 最左前缀原则:顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上, 注:如果第一个字段是范围查询需要单独建一个索引 注:在创建多列索引时,要根据 ...