iOS 多线程简单整理NSThread、GCD、NSOperation

iOS Pthreads  NSThread

Pthreads:可以在Unix / Linux / Windows 等系统跨平台使用,使用 C 语言编写,需要程序员自己管理线程的生命周期,使用难度较大

NSThread:是苹果官方提供的,使用起来比 pthread 更加面向对象,简单易用,可以直接操作线程对象。不过也需要需要程序员自己管理线程的生命周期(主要是创建),运用OC语言。

//使用类方法创建线程执行任务

+ (void)detachNewThreadWithBlock:(void (^)(void))block ;

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

//判断当前是否为多线程

+ (BOOL)isMultiThreaded;

//设置当前线程优先级//指定线程对象优先级 0.0~1.0,默认值为0.5

+ (BOOL)setThreadPriority:(double)p;

//实例方法初始化,需要再调用start方法

- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;

- (instancetype)initWithBlock:(void (^)(void))block;

另外,还有一个NSObject的分类,瞅一眼:

//隐式的创建并启动线程,并在指定的线程(主线程或子线程)上执行方法。

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;

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

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;

线程相关用法

+ (NSThread *)mainThread; // 获得主线程

- (BOOL)isMainThread;// 判断是否为主线程(对象方法)

+ (BOOL)isMainThread;// 判断是否为主线程(类方法)

NSThread *current = [NSThread currentThread]; // 获得当前线程

- (void)setName:(NSString *)n;// 线程的名字——setter方法

  • (NSString *)name;// 线程的名字——getter方法

线程状态控制方法

启动线程方法 // 线程进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态

- (void)start;

阻塞(暂停)线程方法// 线程进入阻塞状态

+ (void)sleepUntilDate:(NSDate *)date;//当前线程暂停到某个时间

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;//当前线程暂停一段时间

强制停止线程 // 线程进入死亡状态

+ (void)exit; 退出当前线程

// 在主线程上执行操作

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

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;

// equivalent to the first method with kCFRunLoopCommonModes

// 在指定线程上执行操作

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

// 在当前线程上执行操作,调用 NSObject  performSelector:相关方法

- (id)performSelector:(SEL)aSelector;

- (id)performSelector:(SEL)aSelector withObject:(id)object;

- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

iOS GCD

GCD:全名Grand Central Dispatch,中文名郭草地,是基于C语言的一套多线程开发API.替换NSThread等线程技术,充分利用了设备多核(自动),使用C语言。

任务管理方式——队列

两个通用队列:

串行队列:所有任务会在一条线程中执行(有可能是当前线程也有可能是新开辟的线程),并且一个任务执行完毕后,才开始执行下一个任务。(等待完成)

并行队列:可以开启多条线程并行执行任务(但不一定会开启新的线程),并且当一个任务放到指定线程开始执行时,下一个任务就可以开始执行了。(等待发生)

两个特殊队列:

主队列:系统为我们创建好的一个串行队列,牛逼之处在于它管理必须在主线程中执行的任务,属于有劳保的。

全局队列:系统为我们创建好的一个并行队列,使用起来与我们自己创建的并行队列无本质差别。

任务执行方式(GCD给出了两种执行方式——同步执行(sync)和异步执行(async))

同步执行:在当前线程执行任务,不会开辟新的线程。必须等到Block函数执行完毕后,dispatch函数才会返回。

异步执行:可以在新的线程中执行任务,但不一定会开辟新的线程。dispatch函数会立即返回, 然后Block在后台异步执行。

任务队列组合方式

GCD其他函数用法

GCD 延时执行方法:dispatch_after//该函数用于任务延时执行

GCD 一次性代码(只执行一次):dispatch_once//保证函数在整个生命周期内只会执行一次

GCD 队列组:dispatch_group//队列组,当加入到队列组中的所有任务执行完成之后,会调用dispatch_group_notify函数通知任务全部完成

GCD 栅栏方法:dispatch_barrier_async//使用此方法创建的任务,会查找当前队列中有没有其他任务要执行,如果有,则等待已有任务执行完毕后再执行,同时,在此任务之后进入队列的任务,需要等待此任务执行完成后,才能执行

GCD 快速迭代方法:dispatch_apply//该函数用于重复执行某个任务,如果任务队列是并行队列,重复执行的任务会并发执行,如果任务队列为串行队列,则任务会顺序执行,需要注意的是,该函数为同步函数,要防止线程阻塞和死锁

GCD 信号量:dispatch_semaphore//信号量是控制任务执行的重要条件,当信号量为0时,所有任务等待,信号量越大,允许可并行执行的任务数量越多

NSOperation && NSOperationQueue

NSOperation以及NSOperationQueue是苹果对于GCD的封装,其中呢,NSOperation其实就是我们上面所说的任务,但是这个类不能直接使用,我们要用他的两个子类,NSBlockOperation和NSInvocationOperation,而NSOperationQueue呢,其实就是类似于GCD中的队列,用于管理你加入到其中的任务。

NSOperation

它提供了关于任务的执行,取消,以及随时获取任务的状态,添加任务依赖以及优先级等方法和属性,相对于GCD提供的方法来说,更直观,更方便,并且提供了更多的控制接口。

- (void)start;//启动任务 默认加入到当前队列

- (void)main;//自定义NSOperation,写一个子类,重写这个方法,在这个方法里面添加需要执行的操作。

- (void)addDependency:(NSOperation *)op;//添加依赖

- (void)removeDependency:(NSOperation *)op;//移除依赖

@property NSOperationQueuePriority queuePriority;//执行优先级

然而NSOperation本身是个抽象类,不能直接使用,我们有三种方式赋予它新的生命,如下

NSOperation第一个,这是我要说的第一个任务类型,我们可以自定义继承于NSOperation的子类,并重写父类提供的方法,自定义的任务更具有指向性,它可以满足你特定的需求

NSBlockOperation 第二个,就是系统提供的NSOperation的子类NSBlockOperation,我们看一下他提供的API:

@interface NSBlockOperation : NSOperation {

@private

id _private2;

void *_reserved2;

}

+ (instancetype)blockOperationWithBlock:(void (^)(void))block;

- (void)addExecutionBlock:(void (^)(void))block;

@property (readonly, copy) NSArray *executionBlocks;

@end

NSInvocationOperation 第三个,就是它了,同样也是系统提供给我们的一个任务类,基于一个target对象以及一个selector来创建任务,具体代码:

-(void)NSInvocationOperationRun{

NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];

[invocationOper start];

}

-(void)invocationOperSel{

NSLog(@"NSInvocationOperationRun_%@",[NSThread currentThread]);

}

NSOperationQueue

上面说道我们创建的NSOperation任务对象可以通过start方法来执行,同样我们可以把这个任务对象添加到一个NSOperationQueue对象中去执行

- (void)addOperation:(NSOperation *)op;//添加任务

- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//添加一组任务

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//添加一个block形式的任务

-(void)NSOperationQueueRun{

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

NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];

[queue addOperation:invocationOper];

NSBlockOperation *blockOper = [NSBlockOperation blockOperationWithBlock:^{

NSLog(@"NSBlockOperationRun_%@",[NSThread currentThread]);

}];

[queue addOperation:blockOper];

[queue addOperationWithBlock:^{

NSLog(@"QUEUEBlockOperationRun_%@",[NSThread currentThread]);

}];

}

任务的优先级

添加依赖关系

队列的最大并发数

线程锁 NSLock @synchronized(要传入一个同步对象(一般就是self),然后将你需要加锁的资源放入代码块中,如果该资源有线程正在访问时,会让其他线程等待)

猜你喜欢

转载自blog.csdn.net/sinat_32283541/article/details/85556834
今日推荐