iOS多线程实现

以下是对iOS实现多线程的介绍,阅读前需先对线程有一定的了解

线程生命周期


线程生命周期

iOS实现多线程的方式

NSThread

GCD

NSOperation

NSThread实现多线程

NSThread是线程类,创建一个NSThread就是创建一个线程

NSThread创建线程的几种方式:

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

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

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

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

detach开头的类方法,在线程创建 的同时,会运行线程。

实例初始化的线程,则需要主动调用start方法,启动线程。调用start方法之后,线程立即进入就绪状态,等待系统的调度,然后线程就在运行和就绪状态之间来回切换,直到事务完成。

这里的block和selector是线程需要执行的事务,当事务执行完成之后该线程就可以被释放了(死亡状态)。

除了事务执行,在线程出错,或者调用thread的exit方法后,线程也会dead。

线程状态

isExecuting:是否正在执行

isFinished:是否结束

isCanceled:是否取消

调用Thread的cancel方法,并不能真的取消线程事务,只能把isCanceled变成YES

如果需要取消线程,可以向线程发送一个信号(比如调用cancel方法,把isCanceled变成YES),在线程事务中判断这个信号,当线程收到终止信号,程序终止事务或者调用exit(例如事务是一个循环,在循环体中必要的地方判断isCanceled是否为YES,当为YES的时候跳出循环体,终止事务)。

尽量不要用exit结束线程(具体原因忘记了,等找到,再补回来)

线程睡眠

调用sleepXX 方法可以暂停线程一段时间,使线程进入阻塞状态。

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

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

线程优先级

threadPriority代表线程优先级,是一个double类型,区间为:0~1,1代表最高优先级,0代表最底优先级。

NSThread默认优先级是0.5。

优先级高的线程获取更多的执行机会。

线程同步与线程通信

使用@synchronized代码块实现同步

被@synchronized修饰的代码块可简称为同步代码块。

@synchronized(obj) {

...

}

同步代码块是为了防止多个线程同时访问同一个资源(obj),

obj就是同步监视器,只有获得了对obj的锁定(或者资源访问机会,类似对obj加了同步锁),才能执行下面的代码块。

要正确的选用监视器(obj)

代码块里的代码要尽可能的短,最好只放入访问和修改obj 的代码

同步锁(NSLock)

NSLock也是控制多线程对临界资源访问的工具,每次只有一个线程可以NSLock进行锁定。

[lock lock];

...

[lock unlock];

synchronized和NSLock锁的是什么?谁才是临界资源?

lock是锁,临界资源放在锁中间,大家都遵守协议(只有获取到锁,才可以访问临界资源)才能做到对临界资源的同步访问。

NSRecursiveLock(递归锁)

NSCondition线程通信

以上的同步方法都是被动同步,当线程访问的资源被锁定以后,之后被动排队,等待资源释放。NSCondition是线程的主动同步,例如:线程A的任务是基于线程B的任务的结果之上的,线程A利用NSCondition主动等待,当线程B的任务完成以后,利用NSCondition通知线程A,线程A收到通知后结束等待,完成自己的任务。

NSCondition也实现了NSLocking协议,所以NSCondition也可以当做锁来使用,并在锁的基础上加了wait、signal,broadcast等功能。普通的lock实现的被动同步是无序的,谁先获得资源谁先执行,加入了wait、signal,broadcast功能的Condition可以实现有序的同步。

例如,生产者和消费者同步。

使用NSLock,如果消费者先获取到产品库的使用权,会先消费,但是这时候还没有生产,产品库是空的,消费不了,然后释放使用权,接着生产者获取产品库使用权,生产产品。这显然不是一个正确的顺序。

使用NSCondition,如果消费者先获取到产品库的使用权,判断是否有产品,没有就wait等待,然后生产者获取使用权,开始生产,完成后signal通知消费者。消费者收到通知,开始消费。

- (void)wait;

让当前线程等待

- (void)signal;

通知某一个等待的线程,可以继续了

- (void)broadcast;

通知所有等待的线程,可以继续了

GCD实现多线程

GCD的优点

GCD可以管理线程。使用GCD实现多线程只需两步,创建队列,将任务提交给队列。队列负责管理开发者提交的任务,每一个队列都已一个线程池,用来管理线程。 控制线程的同步、并发、生命周期管理是一个非常复杂的过程,而对于开发者来说,更关心的是待处理的任务。GCD队列对多线程进行了封装,使得开发者从管理多线程的复杂工作中脱离出来,把每一个任务封装成一个block工作单元。开发者把这些工作单元放入GCD队列中,由队列来进行创建、管理线程的工作(这个过程对开发者不可见),这样开发者就可以专心处理自己的任务了。

队列的种类:

串行队列:线程池只有一个线程,任务以串行执行。

并发队列:线程池有多个线程,任务以FIFO的顺序并发启动执行。

创建队列

dispatch_queue_t dispatch_get_current_queue(void);

获取当然任务所在的队列

dispatch_queue_t dispatch_get_main_queue(void)

获取主队列:(一个串行队列,只有一个UI线程)

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);

获取系统全局并发队列。可以指定优先级。

dispatch_queue_t dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr);

创建一个串行或者并发队列

向队列提交任务

void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

异步向队列提交任务。

void dispatch_apply(size_t iterations, dispatch_queue_t queue,

DISPATCH_NOESCAPE void (^block)(size_t));

异步向队列提交多个相同的任务。串行的时候,可以理解为一个任务执行了多次,但是并发的时候,这几个任务是并发执行的。

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

某个时刻,异步向队列提交任务。

NSOperation&NSOperationQueue实现多线程

优势

NSOperationQueue的实现原理和GCD类似,NSOperationQueue也有一个线程池,来管理多线程的操作,开发者只需要关注与任务的分发。与GCD不同的是,GCD的接口是C类型接口,NSOperationQueue的接口是面向对象类型的接口。GCD的每个任务是一段代码段,NSOperationQueue的每个任务是一个NSOperation对象。GCD的任务对比与NSOperation的优势是,简单方便,创建一个任务只需要一段断码段即可,而NSOperation需要创建一个对象,复杂的任务还需要实现一个NSOperation子类。GCD任务的劣势是,无法对任务进行控制,当一个任务提交到队列上以后,很难取消该任务,或者获取该任务的进度。而NSOperation可以有效控制任务的进度,甚至可以灵活地取消任务,甚至整个队列的任务都能取消。而且NSOperationQueue很容易控制最大并发数,GCD队列控制起来就比较复杂。NSOperationQueue还可以灵活地暂停任务的分发。

NSOperationQueue可以设置最大并发数,当最大并发数为1的时候,就是串行队列,>1的时候,就是并发队列。

队列

- (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);

提交任务,任务也可以是一个简单的代码块。

@property NSInteger maxConcurrentOperationCount;

最大并发数

@property (getter=isSuspended) BOOL suspended;

暂停

@property (nullable, assign ) dispatch_queue_t underlyingQueue;

底层对应的GCD队列

- (void)cancelAllOperations;

取消队列中所有任务

- (void)waitUntilAllOperationsAreFinished;

阻塞当前线程,知道队列中的所有任务完成。

任务(操作)

NSOperation一般不会直接拿来用,而是实现它的子类,或者是用现有的几个简单的子类NSBlockOperation、NSInvocationOperation(以代码块、函数作为任务)。

- (void)start;

开始任务

- (void)main;

任务主体,子类要重写这个方法来实现自己的任务

@property (readonly, getter=isCancelled) BOOL cancelled;

是否被取消,由cancel方法来改变这个值

- (void)cancel;

取消任务,这个和NSThread里的cancel一样,只能改变cancelled的值,具体取消需要子类来完成。

@property (readonly, getter=isExecuting) BOOL executing;

是否正在执行

@property (readonly, getter=isFinished) BOOL finished;

是否执行完成

@property (readonly, getter=isConcurrent) BOOL concurrent;

是否并发

@property (readonly, getter=isAsynchronous) BOOL asynchronous

是否异步

@property (readonly, getter=isReady) BOOL ready;

是否就绪

- (void)addDependency:(NSOperation *)op;

- (void)removeDependency:(NSOperation *)op;

添加、移除,“基于”任务。(该任务是基于这些任务的,只有这些基础任务执行完,该任务才可以执行)

@property (nullable, copy) void (^completionBlock)(void)

任务结束回调,当任务结束时调用。

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

推荐阅读更多精彩内容