OC中多线程的操作方法
- Pthread
- NSThread
- GCD
NSOperation
Pthread基本不会使用(因为太难了-_-),了解下,当做知识面的扩展
NSThread在项目中也不怎么使用,使用最多的或许就是调试代码,虽然很简单。。但是没有其他的好用
[NSThread currentThread];//用来查看是当前的方法在哪个线程中
[NSThread mainThread];//得到主线程
//通过NSThread创建子线程通过代码启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
//耗时操作最好创建一个子线程
[self performSelectorInBackground:@selector(方法名) withObject:self];
//通过NSThread来创建子线程并启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
//在子线程需要关于UI的操作,要回到主线程,waitUntilDone参数代表是否在方法执行完之后再向下顺序执行语句
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
关于NSThread的一些操作
//取消线程
- (void)cancel;
//启动线程
- (void)start;
//判断某个线程的状态的属性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
//设置和获取线程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
//获取当前线程信息
+ (NSThread *)currentThread;
//获取主线程信息
+ (NSThread *)mainThread;
//使当前线程暂停一段时间,或者暂停到某个时刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
GCD经常使用
GCD中有两个新的概念:任务和队列任务:说白了,就是要执行的代码
任务有两种执行方式:同步执行和异步执行,两种的区别在于会不会堵塞当前线程,同步执行会堵塞当前线程直到block块的代码执行完毕,而异步执行不会队列:就是要在哪里执行,是串行还是并发,串行就是一个一个的去执行,并发是几个任务可以一起执行,
这里有一点要注意:串行和并发都是遵循FIFO的规则(先进先出),不同的是并发执行是CPU将一个一个block块放在不同的线程去完成,所以如果任务很多,它并不会让所有任务同时执行
举个栗子说明一下:这里用到了主队列,主队列是什么?就是主线程,从程序开始就创建的线程,用于UI刷新等等,所以一般耗时的任务还是交给子线程去处理。主队列是一个特殊的串行队列。
/**
* 同步函数 + 主队列:这样写会造成程序堵塞,造成死锁现象
*/
- (void)syncMain
{
NSLog(@"syncMain --- Beign");
//1.获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.将任务加入主队列,这里执行了之后当前线程(主线程)会被堵塞,然后把block块的代码放到主队列执行,但是主线程已经被堵塞,所以程序卡主,造成死锁现象
dispatch_sync(queue, ^{
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
});
}
/**
* 异步函数 + 主队列
*/
- (void)asyncMain
{
NSLog(@"asyncMain --- Begin");
//1.获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.将任务加入主队列,不会阻塞当前线程,所以执行顺序为:Begin-End-123
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"asyncMain --- End");
}
/**
* 同步函数 + 串行队列:不会开辟新线程,会阻塞当前队列(主队列),将block执行完毕
*/
- (void)syncSerial
{
NSLog(@"syncSerial --- Beign");
//1.获取串行队列,第一个参数一般是公司的域名,第二个参数为获取哪一个队列
dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_SERIAL);
//2.将任务加入队列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"syncSerial --- End");
}
/**
* 异步函数 + 串行队列:会开启新的线程,不会阻塞当前队列
*/
- (void)asyncSerial
{
NSLog(@"asyncSerial --- Begin");
//1.获取队列
dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_SERIAL);
//2.将任务加入队列
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"asyncSerial --- End");
}
/**
* 同步函数 + 并行队列:不会开辟新线程,会阻塞当前队列(主队列),把block里面的代码放到当前队列,相当于串行队列
*/
- (void)syncConcurrent
{
NSLog(@"syncConcurrent --- Beign");
//1.获取串行队列,第一个参数一般是公司的域名,第二个参数为获取哪一个队列
dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_CONCURRENT);
//2.将任务加入队列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"syncConcurrent --- End");
}
/**
* 异步函数 + 并行队列:会开启多条新的线程,不会阻塞当前队列
*/
- (void)asyncConCurrent
{
NSLog(@"asyncSerial --- Begin");
//1.获取队列
// dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_CONCURRENT);//自己创建的并行队列
//系统已经创建好的全局并行队列,一般使用这个不用自己创建,第一个参数为优先级,第二个参数暂时无用为0
// #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
// #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
// #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
// #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2.将任务加入队列,执行顺序不一定。
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"asyncSerial --- End");
}
GCD的一些其他用法
//有这么1种需求
//首先:分别异步执行2个耗时的操作
//其次:等2个异步操作都执行完毕后,再回到主线程执行操作
//这时候就可以考虑队列组,
- (void)group
{
//获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建一个队列组
dispatch_group_t group = dispatch_group_create();
//下载图片1
dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
self.image1 = [UIImage imageWithData:data];
});
//下载图片2
dispatch_group_async(group, queue, ^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
self.image2 = [UIImage imageWithData:data];
});
//合成图片
dispatch_group_notify(group, queue, ^{
//开启新的图形
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
//绘制图片
[self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
[self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];
//取得图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//结束上下文
UIGraphicsEndImageContext();
//回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
}
/**
* 快速迭代,将多个任务自动分发给多个线程,快速完成任务,等到全部完成返回值
*/
- (void)apply
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t i) {
NSLog(@"%lu----%@", i, [NSThread currentThread]);
});
}
/**
* 只执行一次的代码,
*/
- (void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"------run");
});
}
/**
* 延迟执行
*/
- (void)delay
{
NSLog(@"touchesBegan-----");
//设置几秒后执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"run-------");
});
}
/**
* 让排在它前面的任务先执行,然后再执行这个任务
*/
- (void)barrer
{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"1----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2----%@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async----3----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"5----%@", [NSThread currentThread]);
});
}
NSOperation
/* * NSOperation是一个抽象类,不能直接用,直接供开发者用的有两种 * 1.NSBlockOperation * 2.NSInvocationOperation * 3.开发者可以继承NSOperation自定义任务 */ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //调用NSBlockOperation的方法 // [self blockOperation]; //调用NSInvocationOperation的方法 // [self invacationOperation]; //让队列执行,如果暂停就执行,如果执行就暂停 // if (self.queue.isSuspended) // { // self.queue.suspended = NO; // } // else // { // self.queue.suspended =YES; // } //取消所有操作 // [self.queue cancelAllOperations]; //依赖操作 [self operationWithDependency]; } //NSBlockOperation的使用比较方便的使用 - (void)blockOperation { NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ //只执行这一句的话在主线程执行,NSOperation对队列的掌控比较好,自动分配队列 NSLog(@"任务1_____%@", [NSThread currentThread]); }]; //还可以对这个操作添加额外的线程(这时候自动在子线程执行这些任务) [op addExecutionBlock:^{ NSLog(@"任务2_____%@", [NSThread currentThread]); }]; [op addExecutionBlock:^{ NSLog(@"任务3_____%@", [NSThread currentThread]); }]; [op addExecutionBlock:^{ NSLog(@"任务4_____%@", [NSThread currentThread]); }]; //写完任务后需要任务开始 [op start]; } //NSInvocationOperation的使用还是比较麻烦的一般不去使用 - (void)invacationOperation { //用来执行一个方法和[self performSelector:@selector(run) withObject:nil];很像,都是在主线程执行 NSInvocationOperation *opInvocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; [opInvocation start]; } - (void)run { NSLog(@"invocationTask______%@", [NSThread currentThread]); } /* * NSOperation还可以创建队列来执行操,用最大并发操作数来设置并行或者串行队列 * 可以向队列里面添加操作有三种 * 1.创建NSInvocationOperation对象添加 * 2.创建NSBlockOperation对象添加 * 3.直接以下面这种方式添加(NSBlockOperation的简单方式) */ - (void)OperationQueue { //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //设置最大并发操作数 /* * 默认值是-1,自动调配队列 * 设置1时,就是串行队列 * 设置>1时,就是并行队列 */ queue.maxConcurrentOperationCount = -1; //添加操作 [queue addOperationWithBlock:^{ NSLog(@"操作1________%@",[NSThread currentThread]); /* * NSOperationQueue 可以选择挂起队列或者恢复队列或者取消操作 * suspended 的值决定了暂停(挂起)或者恢复 * YES:挂起队列 NO:恢复队列 * 调用方法 cancelAllOperations 取消所有操作 * 取消所有操作注意:取消操作后需要把当前的操作执行完毕后,取消排在后面的操作 */ //可以用一个耗时操作来验证一下 // for (NSInteger i = 0; i < 5000; ++i) // { // NSLog(@"操作1____%zd____%@", i, [NSThread currentThread]); // } }]; [queue addOperationWithBlock:^{ NSLog(@"操作2________%@",[NSThread currentThread]); // for (NSInteger i = 0; i < 5000; ++i) // { // NSLog(@"操作2____%zd____%@", i, [NSThread currentThread]); // } }]; [queue addOperationWithBlock:^{ NSLog(@"操作3________%@",[NSThread currentThread]); // for (NSInteger i = 0; i < 5000; ++i) // { // NSLog(@"操作3____%zd____%@", i, [NSThread currentThread]); // } }]; NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"操作4________%@",[NSThread currentThread]); }]; [blockOperation addExecutionBlock:^{ NSLog(@"操作5________%@",[NSThread currentThread]); }]; [queue addOperation:invocationOperation]; [queue addOperation:blockOperation]; self.queue = queue; } /* * 在一个队列中,可以设置依赖,就像GCD中的队列组,让某个操做在一个或几个操作之后进行 */ - (void)operationWithDependency { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; __block UIImage *image1 = nil; // 下载图片1 NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{ // 图片的网络路径 NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"]; // 加载图片 NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片 image1 = [UIImage imageWithData:data]; }]; __block UIImage *image2 = nil; // 下载图片2 NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{ // 图片的网络路径 NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"]; // 加载图片 NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片 image2 = [UIImage imageWithData:data]; }]; // 合成图片 NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{ // 开启新的图形上下文 UIGraphicsBeginImageContext(CGSizeMake(100, 100)); // 绘制图片 [image1 drawInRect:CGRectMake(0, 0, 50, 100)]; image1 = nil; [image2 drawInRect:CGRectMake(50, 0, 50, 100)]; image2 = nil; // 取得上下文中的图片 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文 UIGraphicsEndImageContext(); // 回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; }]; }]; //给合成的操作添加依赖 [combine addDependency:download1]; [combine addDependency:download2]; [queue addOperation:download1]; [queue addOperation:download2]; [queue addOperation:combine]; }