iOS多线程NSThread,GCD ,NSOperation

NSThread:

这套方案是经过苹果封装后的,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。但是,它的生命周期还是需要我们手动管理,所以这套方案也是偶尔用用,比如 [NSThread currentThread],它可以获取当前线程类,你就可以知道当前线程的各种属性,用于调试十分方便。下面来看看它的一些用法。

  • 创建并启动
    -先创建线程类,再启动
// 创建 
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil]; 
// 启动
[thread start];
  • 创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
  • 使用 NSObject 的方法创建并自动启动
[self performSelectorInBackground:@selector(run:) withObject:nil];

GCD

Grand Central Dispatch,它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。

  • 任务和队列

  • 在 GCD中,加入了两个非常重要的概念: 任务队列
    任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行异步执行,他们之间的区别是 是否会创建新的线程。

  • 同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
    如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
    如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。

  • 队列:用于存放任务。一共有两种队列, 串行队列并行队列

  • 串行队列 中的任务会根据队列的定义 FIFO 的执行,一个进来执行完出去,下一个才会进来。

  • 并行队列 根据队列的定义 FIFO 的执行,但它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

  • 创建队列
    主队列:这是一个特殊的 串行队列
    它用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。
    自己创建的队列:~~凡是自己创建的队列都是 串行队列
    。其中第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。大家可以看xcode的文档查看参数意义。

  • 第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL表示创建串行队列。
    传入 DISPATCH_QUEUE_CONCURRENT表示创建并行队列。

NSOperation和NSOperationQueue

  • NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 大家可以看到 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务 和 队列 。操作步骤也很好理解:
  • 将要执行的任务封装到一个 NSOperation 对象中。
  • 将此任务添加到一个 NSOperationQueue 对象中。
添加任务
  • NSOperation
    只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation和NSBlockOperation
    • 创建一个 Operation 后,需要调用start
      方法来启动任务,它会 默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其cancel
//1.创建NSInvocationOperation对象 
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; //2.开始执行
 [operation start];
//1.创建NSBlockOperation对象 NSBlockOperation
 *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }]; 
//2.开始任务 
operation start];

线程同步

  1. 线程同步就是为了防止多个线程抢夺同一个资源造成的数据安全问题,所采取的一种措施
    • 互斥锁 :给需要同步的代码块加一个互斥锁,就可以保证每次只有一个线程访问此代码块。
@synchronized(self) { //需要执行的代码块}
 - **同步执行** :我们可以使用多线程的知识,把多个线程都要执行此段代码添加到同一个串行队列,这样就实现了线程同步的概念。当然这里可以使用 GCD和 NSOperation 两种方案,我都写出来。
//GCD 
//需要一个全局变量queue,要让所有线程的这个操作都加到一个queue中 
dispatch_sync(queue, ^{ 
NSInteger ticket = lastTicket;
 [NSThread sleepForTimeInterval:0.1];
 NSLog(@"%ld - %@",ticket, [NSThread currentThread]);
 ticket -= 1; lastTicket = ticket; 
}); 
//NSOperation & NSOperationQueue 
//重点:1. 全局的 NSOperationQueue, 所有的操作添加到同一个queue中 
// 2. 设置 queue 的 maxConcurrentOperationCount 为 1 
// 3. 如果后续操作需要Block中的结果,就需要调用每个操作的waitUntilFinished,阻塞当前线程,一直等到当前操作完成,才允许执行后面的。waitUntilFinished 要在添加到队列之后! NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ 
NSInteger ticket = lastTicket; 
[NSThread sleepForTimeInterval:1]; 
NSLog(@"%ld - %@",ticket, [NSThread currentThread]); 
ticket -= 1; lastTicket = ticket; }];
 [queue addOperation:operation];
 [operation waitUntilFinished]; //后续要做的事

延迟执行

延迟执行就是延时一段时间再执行某段代码。下面说一些常用方法。
perform

// 3秒后自动调用self的run:方法,并且传递参数:@"abc"
 [self performSelector:@selector(run:) withObject:@"abc" afterDelay:3];

GCD

// 创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 设置延时,单位秒
double delay = 3; 
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{ 
// 3秒后需要执行的任务
});

NSTimer

[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(run:) userInfo:@"abc" repeats:NO];

单例模式

@interface Tool : NSObject <NSCopying>
+(instancetype)sharedTool;
@end
@implementation Toolstatic id _instance;
+(instancetype)sharedTool
 { static dispatch_once_t onceToken; 
  dispatch_once(&onceToken, ^{
 _instance = [[Tool alloc] init]; 
}); 
return _instance;
}
@end

从其他线程回到主线程的方法

NSThread

//Objective-C
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];

GCD

dispatch_async(dispatch_get_main_queue(), ^{
});

NSOperationQueue

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];

转载于http://www.jianshu.com/p/0b0d9b1f1f19

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容