iOS多线程(一)

多线程涉及到的概念:

进程,线程,主线程,任务,队列,死锁,串行,并行,同步,异步,GCD,NSOperation,NSThread

iOS多线程的实现方式:

1. Pthreads 

    具体见:

    https://www.jianshu.com/p/0b0d9b1f1f19


图. iOS多线程技术比较

2. NSThread

(一)创建方法:

NSThread*thread = [[NSThreadalloc] initWithTarget:selfselector:@selector(run:) object:nil];

创建并自动启动 [NSThread detachNewThreadSelector:@selector(run:) toTarget:selfwithObject:nil];

+ (void)detachNewThreadWithBlock:(void(^)(void))blockAPI_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullableid)argument;

// equivalent to the first method with kCFRunLoopCommonModes

- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullableid)argAPI_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

等等

(二)线程休眠方法

+ (void)sleepUntilDate:(NSDate*)date;

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

(三)强制退出线程

    + (void)exit;

(四)线程安全

多个线程访问同一个数据,加互斥锁

    @synchronized (self)

    {

        //访问临界区

    }


(五)线程通信

由子线程回归主线程

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullableid)arg waitUntilDone:(BOOL)wait modes:(nullableNSArray *)array;

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullableid)arg waitUntilDone:(BOOL)wait;

//waitUntilDone YES aSelector执行完再去执行后续代码,NO 并发执行 

- (void)performSelector:(SEL)aSelector onThread:(NSThread*)thr withObject:(nullableid)arg waitUntilDone:(BOOL)wait modes:(nullableNSArray *)arrayAPI_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

- (void)performSelector:(SEL)aSelector onThread:(NSThread*)thr withObject:(nullableid)arg waitUntilDone:(BOOL)waitAPI_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

敬请期待:

3. GCD

任务:执行什么操作

队列:用来存放任务

GCD使用:1.定制任务(确定想做的事情),2.将任务添加到队列(GCD会自动将队列的任务取出,放到对应的线程中执行,任务的取出遵循队列的FIFO原则)

执行任务的方式:

同步任务,

    dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)

异步任务,

    dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)

同步和异步任务的区别:

dispatch_sync和 dispatch_async需要两个参数,一个是队列,一个是block,它们的共同点是block都会在你指定的队列上执行(无论队列是并行队列还是串行队列),不同的是dispatch_sync会阻塞当前调用GCD的线程直到block结束,而dispatch_async异步继续执行。

同步,在当前线程中执行任务,不具备开启新的线程的能力。

异步,可以在block中开启新的线程。

并发队列和串行队列:

并发队列可以让多个任务并发(同时)执行,(可以自动开启多个线程同时执行任务),只能在dispatch_async中开启并发队列。

串行队列,让任务一个一个执行

并行队列的创建:

    1. dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t  _Nullable attr#>)

label:队列名称

attr:队列属性,(DISPATCH_QUEUE_CONCURRENT )表示并行队列

    2. dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)

identifier:队列标识

flags:0


串行行队列的创建:

    1. dispatch_queue_create(<#const char * _Nullable label#>,DISPATCH_QUEUE_SERIAL)

DISPATCH_QUEUE_SERIAL 或者NULL表示串行队列。

   2.  dispatch_get_main_queue()

主队列是 GCD自带的一种特殊串行队列,放在主队列中的任务都会在主线程中执行。


并发队列加上同步任务不会开启新的线程,任务逐个执行。

并发队列加上异步任务,会开启新的线程,任务并发执行。

全局队列中加同步任务,不会开启新的线程,任务逐个执行。

全局队列中加异步任务,开启新的线程,任务并发执行的。

串行队列加上异步任务会开启新的线程,任务逐个执行。

主队列(串行队列)(只有一个线程)加上同步任务,造成死锁。

主队列(串行队列)(只有一个线程)加上异步任务,不会创建新的线程。

注意区分全局队列和主队列。

线程通信


dispatch_asyn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

    //耗时操作

    //加载网络图片

    //回到主线程

     dispatch_syn(dispatch_get_main_queue(),^{

        self.imageView = image;

    })

    //继续线程操作

})

4.NSOperation

https://www.jianshu.com/p/a41f1e69ce44 

文章写的很详细。

NSOperation 只是对执行代码的封装,本身并不提供任何的异步功能,NSOperationQueue 底层是基于 GCD 的封装,所以一般来说,我们会用 NSOperationQueue 来控制 operation 的执行,queue 会根据 operation 的优先级、依赖等来决定如何执行添加进 queue 的 operation。

1. NSInvocationOperation

//创建NSInvocationOperation对象

NSInvocationOperation*invoOperation = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doSomeThing) object:nil];

//调用start

方法来执行操作[invoOperation start];

注意⚠️:

默认情况下,调用start方法不会开启一条新的线程去执行操作,而是在当前线程同步执行操作。

只有将NSOperation放到NSOperationQueue中,才会异步执行操作。


2. NSBlockOperation

//创建NSBlockOperation对象

NSBlockOperation*blockOperation1 = [NSBlockOperationblock OperationWithBlock:^{NSLog(@"create1----%@",[NSThread currentThread]); }];

//通过addExecutionBlock:方法添加更多的操作

[blockOperation1 addExecutionBlock:^{NSLog(@"add1-----%@",[NSThreadcurrentThread]); }];

[blockOperation1 start];

[blockOperation2 start];

可以看出NSBlockOperation如果封装了多个操作,那么除了第一个操作外,其他的操作会在子线程中进行。如果只封装了一个操作,默认在主线程中进行,并且只要NSBlockOperation封装的操作数大于一个,就会异步执行操作。


3. 自定义NSOperation

自定义NSOperation可以通过重写 main 或者start方法 来定义自己的 operations

使用 main方法非常简单,开发者不需要管理一些状态属性(例如 isExecuting 和 isFinished),当 main 方法返回的时候,这个 operation 就结束了。这种方式使用起来非常简单,但是灵活性相对重写 start 来说要少一些, 因为main方法执行完就认为operation结束了,所以一般可以用来执行同步任务。

重写main方法有一个注意点:

需要自己创建自动释放池(如果是异步操作,无法访问主线程的自动释放池)

为了能使用操作队列所提供的取消功能,你需要在长时间操作中时不时地检查 isCancelled属性


NSOperation Queue

将NSOperation添加到NSOperationQueue中,系统会异步执行NSOperation的操作

将NSOperation添加到NSOperationQueue方法

1. addOperation

2.addOperationWithBlock

GCD队列:全局队列,主队列,自定义串行队列,自定义并行队列

NSOperation的队列:主队列,自己定义队列



NSOperation的线程通信

NSOperationQueue *queue =[ [NSOperationQueue alloc]init];

[queue addOperationWithBlock:^{

    //获取网络图片(耗时操作)

    //获取主线程

    [[NSOperationQueue mainQueue]addOperationWithBlock:^{

        //主线程显示图片

        slef.imageView.image = image;

    }];

}];



NSOperation 任务依赖

//添加操作依赖

[blockOperation1 addDependency:blockOperation2]; 

[blockOperation3 addDependency:blockOperation1];

//添加操作到NSOperationQueue

[myQueue addOperation:blockOperation1];

 [myQueue addOperation:blockOperation2]; 

 [myQueue addOperation:blockOperation3];

先执行blockOperation2,再执行blockOperation1,最后执行blockOperation3。

NSOperation并发与取消,挂起

//NSOperationQueue最大并发数量

可以设置maxConcurrentOperationCount 

//取消队列的所有操作

[myQueue cancelAllOperations];

//取消某一个操作

[blockOperation2 cancel];

[myQueue setSuspended:YES];

myQueue.suspended = YES;

最大并发操作数量:

队列中最多同时运行几条线程。虽然NSOperationQueue类设计用于并发执行Operations,你也可以强制单个queue一次只能执行一个Operation。setMaxConcurrentOperationCount:方法可以配置queue的最大并发操作数量。设为1就表示queue每次只能执行一个操作。不过operation执行的顺序仍然依赖于其它因素,比如operation是否被取消(if(self.cancelled))和operation的优先级等。因此串行化的operation queue并不等同于GCD中的串行dispatch queue.

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