关于iOS 多线程有关知识

多线程

GCD

1.任务和队列:

  任务:要做什么,一段代码,在GCD中就是Block,任务有同步执行sync和异步执行async,二者区别是是否开辟新线程.

     sync 阻塞当前进程并等待Block中任务执行完毕,然后线程才能继续执行下去

     async 当前线程会直接往下执行,不会阻塞当前线程

 队列:用于存放任务 串行队列和并行队列

串行队列:FIFO 一个一个先进后出执行

并行队列:并行队列中的任务也是FIFO取出来,不同的是,它取出来一个放到别的线程,然后再取出来一个又放到别的线程,由于取得动作快,看起来就是一起执行的,GCD会根据系统资源控制并行的数量,如果任务很多,不会让所有任务同时执行。

2.创建队列:

主队列:刷新UI,任何需要刷新UI的操作都在主队列进行,一般耗时的任务都放到别的线程执行

let queue = ispatch_get_main_queue()

自己创建的队列:第一个参数是标识符,用于DEBUG的时候标示唯一的队列,可以为空;第二个参数标示创建的队列是串行的还是并行的,nil或DISPATCH_QUEUE_SERAIL表示创建的是串行队列,参数DISPATCH_QUEUE_CONCURRENT表示创建的是并行队列

//串行队列

let queue = dispatch_queue_create("my.bourne.testqueue",nil)

let queue = dispatch_queue_create("my.bourne.testqueue",DISPATCH_QUEUE_SERIAL)

//并行队列

let queue = dispatch_queue_create("my.bourne.testqueue", DISPATCH_QUEUE_CONCURRENT)

全局并行队列:这是系统提供的一个并发队列

let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

3.创建任务

同步任务:会阻塞当前线程

dispatch_sync()

异步任务:不会阻塞当前线程

dispatch_async()

死锁:dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中,可是 main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。

NSOperation NSOperationQueue

    对GCD的封装,完全面向对象分别对应GCD中的任务和队列,执行的任务封装到一个NSOperation,再将任务添加到一个NSOperationQueue然后系统自动执行任务

NSOperation是一个抽象类,不能封装任务,它的两个子类可以封装任务,分别是NSInvocationOperation和NSBlockOpreation,前者是类型不安全,不建议使用

NSBlockOperation

let operationn = NSOperation({

in

//要执行代码。。。。

})

operation.start()

默认在当前线程执行,但是NSBlockOperation有个方法 addExecutionBlock通过这个方法可以给Operation 添加多个执行Block,block 会并发执行

主队列

多线程方案中都有一个主线程,这个特殊的线程必须串行,添加到主队列的任务都会一个接一个地排着队在主线程处理,通过单独的一个类方法来获得主队列

//

let queue = NSOperationQueue.mainQueue()

其他队列

通过初始化方法产生的队列就是其他队列了,因为只有这两种队列,除了主队列,其他队列就不需要名字了。其他队列的任务会在其他线程并行执行。

//创建其他队列

let queue = NSOperationQueue()

//创建NSBlockOperation对象

let operation = NSBlockOperation({

//.....执行的代码

})

queue.addOperation(operation)

    与GCD队列比较,这里没有串行队列,如果要实现多个任务在其他线程串行,可以使用NSOperationQueue的参数 maxConCurrentOperationCount最大并发数,用来设置最多可以让多少个任务同时执行,当设置为1时,就是串行了;NSOperationQueue还有一个添加任务的方法,addOperationWithBlock({block}),添加一个任务到队列中,十分方便。NSOperation还有一个实用功能,就是添加依赖,如有三个任务,A:从服务器下载一张图片;B:给这张图片加个水印,C:把图片返回给服务器,这时候就用到依赖了.

//任务一:下载图片

let operation1 = NSBlockOperation({

NSLog(“下载图片 - %@”,NSThread.currentThread)

NSThread.sleepForTimeInterval(1.0)

})

//任务二:打水印

let operation2 = NSBlockOperation({

NSLog(“打水印 - %@”,NSThread.currentThread)

NSThread.sleepForTimeInterval(1.0)

})

//任务三:上传图片

let operation3 = NSBlockOperation({

NSLog("上传图片 - %@",NSThread.currentThread)

NSThread.sleepForTimeInterval(1.0)

})

//4.设置依赖

operation2.addDependency(operation1)//任务二依赖任务一

operation3.addDependency(operation2)//任务三依赖任务二

//5.创建队列并加入任务

let queue = NSOperationQueue()

queue.addOperations([operation3, operation2, operation1],waitUntilFinished: false)

注意:1.不能添加相互依赖,会死锁

2.可以使用removeDependency来解除依赖关系

3.可以在不同的队列之间依赖,反正就是这个依赖是添加到任务身上的,和队列没有关系。

还有一些常用的方法:

NSOperation

BOOL executing:判断任务是否在正在执行

BooL finished 判断任务是否完成

void(^completionBlock)(void)用来设置完成后需要执行的操作

cancel 取消任务

waitUntilFinished()

NSOperationQueue

NSUInterger operationCount 队列的任务数

cancelAllOperations取消队列中的所有任务

waitUntilAllOperationsAreFinished 阻塞当前线程直到此队列中的所有任务执行完毕

queue setSuspended true 暂停队列

queue setSuspended false 继续

线程同步:

   所谓线程同步就是为了防止多个线程抢夺同一个资源造成的数据安全问题,所采取的一种措施,有很多实现方法。

1.互斥锁:给需要同步的代码块添加一个互斥锁,就可以保证每次只有一个线程访问此代码块

objc_sync_enter(self)

//需要执行的代码块

objc_sync_exit(self)

2.同步执行:我们可以使用多线程的知识,把多个线程都要执行此段代码添加到同一个串行队列,这样就实现了线程同步的概念,这里可以使用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,阻塞当前线程

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{

NSInteger ticket = lastTicket;

[NSThread sleepForTimeInteval:1];

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

ticket -= 1;

lastTicket = ticket;

}]

[queue addOperation: operatin];

[operation waitUntilFinished];

//后续要做的事情

延迟执行

延迟一段时间再试行某段代码

perform

//3秒后自动调用self的run:方法,并且传递参数:@“abc”

[self performSelector :@selector(run:) withObject:@"abc", afterDelay: 3];

GCD

GCD中的disatch_after方法。

//创建队列

dispatch_queue_t queue = diapatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0);

//设置延时,单位秒

double delay = 3;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delay* NESC_PER_SEC)), queue, ^{

//3秒后要执行的操作

})

NSTimer

[NSTimer scheduledTimerWithTimeInterval: 3.0 target: self selector:@selector(run:)]

单例模式

oc

@interface Tool:NSObject

+(instancetype) shareTool;

@end

@implementation Tool

static id_instance;

+(instancetype) shareTool {

static dispatch_once_t oneToken;

dispatch_once(&onceToken, ^{

_instance = [[Tool alloc] init];

})

return _instance;

}

@end

swift

class Tool: NSObject {

static let shareTool = Tool()

//私有化构造方法,阻止其他对象使用这个类的默认的“()”构造方法

private override init() {}

}

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

我们都知道在其他线程操作完成后必须要回到主线程更新UI,以下是一些方法回到主线程

NSThread

[self performSelectorOnMainThread:@selector(run) withObject: nil waitUnitilDone:NO];

GCD

//OC

dispatch_async(dispatch_get_main_queue, ^{

//....执行代码,刷新UI

})

//swift

dispatch_async(dispatch_get_main_queue, {

//执行刷新UI操作

})

NSOperationQueue

//oc

[[NSOperationQueue mainQueue] addOperationWithBlock:^ {

}];

//swift

NSOperationQueue.mianQueue().addOperationWithBlock{}

原文地址:http://www.jianshu.com/p/0b0d9b1f1f19

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

推荐阅读更多精彩内容

  • 在这篇文章中,我将为你整理一下 iOS 开发中几种多线程方案,以及其使用方法和注意事项。当然也会给出几种多线程的案...
    伯恩的遗产阅读 274,342评论 251 2,331
  • 在这篇文章中,我将为你整理一下 iOS 开发中几种多线程方案,以及其使用方法和注意事项。当然也会给出几种多线程的案...
    张战威ican阅读 600评论 0 0
  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 789评论 0 3
  • 学习多线程,转载两篇大神的帖子,留着以后回顾!第一篇:关于iOS多线程,你看我就够了 第二篇:GCD使用经验与技巧...
    John_LS阅读 604评论 0 3
  • 高楼沉月,石砌坠叶,为怜玉颜憔悴。冷香袭人依旧,可堪蹙眉。晚阳立尽惆怅,怎奈何、襟袖惹泪。暮霭淡,罗袂寒,...
    金鱼没头脑阅读 261评论 0 0