IOS多线程的方式
2019-05-09 本文已影响3人
越天高
pthread的基本使用(需要包含头文件)
需要#import <pthread.h>
//使用pthread创建线程对象
pthread_t thread;
NSString *name = @"wendingding";
//使用pthread创建线程
//第一个参数:线程对象地址
//第二个参数:线程属性
//第三个参数:指向函数的指针
//第四个参数:传递给该函数的参数
pthread_create(&thread, NULL, run, (__bridge void *)(name));
3 NSThread
- (1)NSThread的基本使用
- 第一种创建线程的方式:alloc init.
//特点:需要手动开启线程,可以拿到线程对象进行详细设置
//创建线程
/*
第一个参数:目标对象
第二个参数:选择器,线程启动要调用哪个方法
第三个参数:前面方法要接收的参数(最多只能接收一个参数,没有则传nil)
*/
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"wendingding"];
//启动线程
[thread start];
- 第二种创建线程的方式:分离出一条子线程
//特点:自动启动线程,无法对线程进行更详细的设置
/*
第一个参数:线程启动调用的方法
第二个参数:目标对象
第三个参数:传递给调用方法的参数
*/
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分离出来的子线程"];
- 第三种创建线程的方式:后台线程
//特点:自动启动县城,无法进行更详细设置
[self performSelectorInBackground:@selector(run:) withObject:@"我是后台线程"];
设置线程的属性
//设置线程的名称
thread.name = @"线程A";
//设置线程的优先级,注意线程优先级的取值范围为0.0~1.0之间,1.0表示线程的优先级最高,如果不设置该值,那么理想状态下默认为0.5
thread.threadPriority = 1.0;
线程的各种状态:新建-就绪-运行-阻塞-死亡
//常用的控制线程状态的方法
[NSThread exit];//退出当前线程
[NSThread sleepForTimeInterval:2.0];//阻塞线程
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];//阻塞线程
//注意:线程死了不能复生
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSThread *threadA = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"AA"];
[threadA start];
}
- (void)run:(NSString *)name
{
NSLog(@"--%@", name);
[NSThread sleepForTimeInterval:2.0];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
NSLog(@"----%@", name);
}
- (void)task:(NSString *)name
{
NSLog(@"%@", name);
for (NSInteger i = 0; i<100 ;i++) {
NSLog(@"%zd---%@",i,[NSThread currentThread]);
if (i == 20) {
//[NSThread exit]; //退出当前线程
break; //表示任务已经执行完毕.
}
}
}
线程安全
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//设置中票数
self.totalCount = 100;
self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadA.name = @"售票员A";
self.threadB.name = @"售票员B";
self.threadC.name = @"售票员C";
//启动线程
@synchronized(self) {
[self.threadA start];
[self.threadB start];
[self.threadC start];
}
}
-(void)saleTicket
{
while (1) {
//锁:必须是全局唯一的
//1.注意枷锁的位置
//2.注意枷锁的前提条件,多线程共享同一块资源
//3.注意加锁是需要代价的,需要耗费性能的
//4.加锁的结果:线程同步
@synchronized(self) {
//线程1
//线程2
//线程3
NSInteger count = self.totalCount;
if (count >0) {
for (NSInteger i = 0; i<1000000; i++) {
}
self.totalCount = count - 1;
//卖出去一张票
NSLog(@"%@卖出去了一张票,还剩下%zd张票", [NSThread currentThread].name,self.totalCount);
}else
{
NSLog(@"不要回公司上班了");
break;
}
}
}
}
线程之间的通信
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[ NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
}
- (void)downLoadImage
{
NSURL *url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"当前线程%@", [NSThread currentThread]);
//返回主线程刷新页面
//4.回到主线程显示UI
/*
第一个参数:回到主线程要调用哪个方法
第二个参数:前面方法需要传递的参数 此处就是image
第三个参数:是否等待
*/
//[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
// [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
[self.downloadImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
GCD
- (1)GCD基本知识
- 01 两个核心概念-队列和任务
- 02 同步函数和异步函数
- (2)GCD基本使用【重点】
01 异步函数+并发队列:开启多条线程,并发执行任务
- (2)GCD基本使用【重点】
//1.创建队列
/*
第一个参数:C语言的字符串,标签
第二个参数:队列的类型
DISPATCH_QUEUE_CONCURRENT:并发
DISPATCH_QUEUE_SERIAL:串行
*/
//dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
//获得全局并发队列
/*
第一个参数:优先级
第二个参数:
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"---start--");
//2.1>封装任务2>添加任务到队列中
/*
第一个参数:队列
第二个参数:要执行的任务
*/
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
for (int i = 0; i < 10000; i++) {
NSLog(@"AA%i",i );
}
});
dispatch_async(queue, ^{
NSLog(@"download2----%@",[NSThread currentThread]);
for (int i = 0; i < 10000; i++) {
NSLog(@"BB%i",i );
}
});
dispatch_async(queue, ^{
NSLog(@"download3----%@",[NSThread currentThread]);
for (int i = 0; i < 10000; i++) {
NSLog(@"CC%i",i );
}
});
NSLog(@"---end----");
02 异步函数+串行队列:开启一条线程,串行执行任务
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"download1-------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"AAA%i",i );
}
});
dispatch_async(queue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"BB%i",i );
}
});dispatch_async(queue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"CCC%i",i );
}
});
03 同步函数+并发队列:不开线程,串行执行任务
dispatch_queue_t queue = dispatch_queue_create("520.download.com", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"AAA%i",i );
}
});
dispatch_sync(queue, ^{
NSLog(@"download2--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"BBB%i",i );
}
});
dispatch_sync(queue, ^{
NSLog(@"download3--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"CCC%i",i );
}
});
04 同步函数+串行队列:不开线程,串行执行任务
dispatch_queue_t queue = dispatch_queue_create("download.520.com", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"download1--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"AAA%i",i );
}
});
dispatch_sync(queue, ^{
NSLog(@"download2--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"BBB%i",i );
}
});
dispatch_sync(queue, ^{
NSLog(@"download3--------%@",[NSThread currentThread]);
for (int i = 0; i < 1000; i++) {
NSLog(@"CCC%i",i );
}
});
05 异步函数+主队列:不开线程,在主线程中串行执行任务
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"start");
dispatch_async(queue, ^{
NSLog(@"downLoad ---%@", [NSThread currentThread]);
for (int i = 0; i< 100; i++) {
NSLog(@"AA%i",i);
}
});
dispatch_async(queue, ^{
NSLog(@"downLoad ---%@", [NSThread currentThread]);
for (int i = 0; i< 100; i++) {
NSLog(@"BB%i",i);
}
});
dispatch_async(queue, ^{
NSLog(@"downLoad ---%@", [NSThread currentThread]);
for (int i = 0; i< 100; i++) {
NSLog(@"CC%i",i);
}
});
NSLog(@"end");
06 同步函数+主队列:不开线程,串行执行任务(注意死锁发生)
同步函数+主队列:死锁
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"downloadAA --%@",[NSThread currentThread]);
});
07 注意同步函数和异步函数在执行顺序上面的差异
GCD之间的通信
//0.获取一个全局的队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//1.先开启一个线程,把下载图片的操作放在子线程中处理
dispatch_async(queue, ^{
//2.下载图片
NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"下载操作所在的线程--%@",[NSThread currentThread]);
//3.回到主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
//打印查看当前线程
NSLog(@"刷新UI---%@",[NSThread currentThread]);
});
});
GCD常用函数
- 1.延迟
//1. 延迟执行的第一种方法
//[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
//2.延迟执行的第二种方法
//[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
//3GCD
/*
第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
第三个参数:队列*/
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),queue , ^{
[self task];
});
- 一次性代码
不能放在懒加载中的,应用场景:单例模式
- 一次性代码
- (void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"once only");
});
}
栅栏函数
栅栏函数不能使用全局并发队列
//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//0.获得并发队列
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
//1.异步函数
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_barrier_async(queue, ^{
NSLog(@"++++++++++++++++++++++++");
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
}
});
```
#队列组
06进入群组和离开群组
dispatch_group_enter(group);//执行该函数后,后面异步执行的block会被gruop监听
dispatch_group_leave(group);//异步block中,所有的任务都执行完毕,最后离开群组
/*
1.下载图片1 开子线程
2.下载图片2 开子线程
3.合成图片并显示图片 开子线程
*/
//-1.获得队列组
dispatch_group_t group = dispatch_group_create();
//0.获得并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 1.下载图片1 开子线程
dispatch_group_async(group, queue,^{
NSLog(@"download1---%@",[NSThread currentThread]);
//1.1 确定url
NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
//1.2 下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
//1.3 转换图片
self.image1 = [UIImage imageWithData:imageData];
});
// 2.下载图片2 开子线程
dispatch_group_async(group, queue,^{
NSLog(@"download2---%@",[NSThread currentThread]);
//2.1 确定url
NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
//2.2 下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
//2.3 转换图片
self.image2 = [UIImage imageWithData:imageData];
});
//3.合并图片
//主线程中执行
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"combie---%@",[NSThread currentThread]);
//3.1 创建图形上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
//3.2 画图1
[self.image1 drawInRect:CGRectMake(0, 0, 300, 300)];
self.image1 = nil;
//3.3 画图2
[self.image2 drawInRect:CGRectMake(100, 100, 20, 10)];
self.image2 = nil;
//3.4 根据上下文得到一张图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//3.5 关闭上下文
UIGraphicsEndImageContext();
//3.6 更新UI
// dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"UI----%@",[NSThread currentThread]);
self.imageView.image = image;
// });
});