关于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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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