iOS多线程(一)

多线程涉及到的概念:

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

iOS多线程的实现方式:

1. Pthreads 

    具体见:

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


iOS多线程(一)_第1张图片
图. 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.

你可能感兴趣的:(iOS多线程(一))