ios 线程浅谈

概述

在这里主要讲述线程的基础知识和创建线程的几种方式如:NSThread,NSOPeration 和GCD.以及使用方法和注意事项

一、进程和线程的区别以及线程基础知识

1.进程:系统运行的一个个应用程序,每个程序就是一个进程,进程之间是相互独立的,每个进程运行在其受保护的内存空间内

2.线程:进程要运行起来至少有一个线程存在,线程是进程的执行单元,一个进程的所有任务都在进程中执行,应用程序启动时系统会默认帮我们开启一条线程,叫“主线程“或”UI线程“。 

3.线程串行:一个线程中执行任务是串行的,也就是说如果执行多个任务是一个一个按顺序来的。

4.多线程

4.1.多线程概念:一个应用程序想要执行更多的任务需要进程开辟多个线程,这些线程是并行的,多线程提高了应用程序的执行速率  

4.2.多线程原理:同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象  

 4.3.多线程优点:能适当提高程序的执行效率。能适当提高资源利用率(CPU、内存利用率)。   

4.4多线程缺点:开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能线程越多,CPU在调度线程上的开销就越大程序设计更加复杂:比如线程之间的通信多线程的数据共享                        

主线程的使用注意:别将比较耗时的操作放到主线程中

二、NSThread

优点:比其他两个轻量级创建线程  

 缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

1.创建并启动

// 创建  

NSThread*thread = [[NSThreadalloc] initWithTarget:selfselector:@selector(run:) object:nil];

// 启动 

[thread start];

2.创建创建并自动启动

[NSThreaddetachNewThreadSelector:@selector(run:) toTarget:selfwithObject:nil];

3.方法

//取消线程- (void)cancel;

//启动线程- (void)start;

//判断某个线程的状态的属性@property(readonly, getter=isExecuting)BOOLexecuting;@property(readonly, getter=isFinished)BOOLfinished;@property(readonly, getter=isCancelled)BOOLcancelled;

//设置和获取线程名字-(void)setName:(NSString*)n;-(NSString*)name

;//获取当前线程信息+ (NSThread*)currentThread;

//获取主线程信息+ (NSThread*)mainThread;

//使当前线程暂停一段时间,或者暂停到某个时刻+ (void)sleepForTimeInterval:(NSTimeInterval)time;+ (void)sleepUntilDate:(NSDate*)date;

三、GCD

Grand Central Dispatch 可译为“牛逼的中枢调度器”,GCD是苹果公司为多核的并行运算提出的解决方案,会自动利用更多的CPU内核(比如双核、四核),会自动管理线程的生命周期(创建线程、调度任务、销毁线程),并且程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码。纯c语言,提供了非常多强大的函数。

提示:(1)GCD存在于libdispatch.dylib这个库中,这个调度库包含了GCD的所有的东西,但任何IOS程序,默认就加载了这个库,在程序运行的过程中会动态的加载这个库,不需要我们手动导入  (2)GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法   (3)GCD中的函数大多数都以dispatch开头。

任务和队列

任务

就是操作,你想干的事情,就是一段代码,在GCD中就是一个BLock.添加任务很方便有两种执行方式:并行执行 串行执行,他们的区别是会不会创建新线程。

同步执行:会阻塞当前的线程,并等Block中的任务执行完,然后当前的线程才会向下执行。

异步执行:当前线程会向下执行,不会阻塞当前线程。

队列

用来存放任务,分为串行队列并行队列

串行队列:(Serial Dispatch Queue)GCD 会FIFO(先进先出)地取出来一个,执行一个,然后取下一个,这样一个一个的执行。

并行队列:(Concurrent Dispatch Queue)放到并行队列的任务,GCD 也会FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。

GCD中获得串行有2种途径


(1)使用dispatch_queue_create函数创建串行队列

dispatch_queue_t  dispatch_queue_create(const char *label,  dispatch_queue_attr_t attr); // 队列名称, 队列属性,一般用NULL即可

示例:

dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 创建

dispatch_release(queue); // 非ARC需要释放手动创建的队列

dispatch_queue_create可以创建串行和并行队列,第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。第二个参数用来表示创建的队列是串行的还是并行的,传入DISPATCH_QUEUE_SERIAL或NULL表示创建串行队列。传入DISPATCH_QUEUE_CONCURRENT表示创建并行队列。

(2)使用主队列(跟主线程相关联的队列)

主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行

使用dispatch_get_main_queue()获得主队列

示例:

dispatch_queue_t queue = dispatch_get_main_queue();

GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建


使用dispatch_get_global_queue函数获得全局的并发队列

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此参数暂时无用,用0即可

四、NSOperation 和 NSOperationQueue

NSOperation

是苹果公司对 GCD 的封装,完全面向对象,NSOperation 和NSOperationQueue分别对应 GCD 的任务 队列。操作步骤:

   1.将要执行的任务封装到一个NSOperation对象中。

   2.将此任务添加到一个NSOperationQueue对象

添加任务

NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类

使用NSOperation⼦类的方式有3种:(1)NSInvocationOperation(2)NSBlockOperation (3)自定义子类继承NSOperation,实现内部相应的⽅法

NSInvocationOperation : 需要传入一个方法名。

//1.创建NSInvocationOperation对象

NSInvocationOperation*operation = [[NSInvocationOperationalloc] initWithTarget:selfselector:@selector(run) object:nil];//2.开始执行[operation start];

NSBlockOperation

//1.创建NSBlockOperation对象

NSBlockOperation*operation = [NSBlockOperationblockOperationWithBlock:^{NSLog(@"%@", [NSThreadcurrentThread]);  }];

//2.开始任务[operation start];

NSBlockOperation还有一个方法:addExecutionBlock:,通过这个方法可以给 Operation 添加多个执行 Block。这样 Operation 中的任务会并发执行,它会在主线程和其它的多个线程执行这些任务

自定义Operation

除了上面的两种 Operation 以外,我们还可以自定义 Operation。自定义 Operation 需要继承NSOperation类,并实现其main()方法,因为在调用start()方法的时候,内部会调用main()方法完成相关逻辑。你想要实现什么功能都可以写在里面。除此之外,你还需要实现cancel()在内的各种方法。

创建队列


主队列

每套多线程方案都会有一个主线程这是一个特殊的线程,必须串行。所以添加到主队列的任务都会一个接一个地排着队在主线程处理。

NSOperationQueue*queue = [NSOperationQueuemainQueue];

其他队列

//1.创建一个其他队列NSOperationQueue*queue = [[NSOperationQueuealloc] init];

//2.创建NSBlockOperation对象NSBlockOperation*operation = [NSBlockOperationblockOperationWithBlock:^{NSLog(@"%@", [NSThreadcurrentThread]);}];

//3.添加多个Blockfor(NSIntegeri =0; i <5; i++) {    [operation addExecutionBlock:^{NSLog(@"第%ld次:%@", i, [NSThreadcurrentThread]);    }];}

//4.队列添加任务[queue addOperation:operation];


NSOperationQueue有一个参数maxConcurrentOperationCount最大并发数,用来设置最多可以让多少个任务同时执行。当你把它设置为1的时候,就是串行

NSOperationQueue还有一个添加任务的方法,- (void)addOperationWithBlock:(void (^)(void))block;,这样就可以添加一个任务到队列中

NSOperation有一个非常实用的功能,那就是添加依赖。比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:

注意:不能添加相互依赖,会死锁,比如 A依赖B,B依赖A。

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

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

其他方法

以上就是一些主要方法, 下面还有一些常用方法需要大家注意:

NSOperation

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

BOOL finished;                    //判断任务是否完成

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

- (void)cancel;                    //取消任务

- (void)waitUntilFinished;            //阻塞当前线程直到此任务执行完毕

NSOperationQueue

NSUInteger operationCount;        //获取队列的任务数

- (void)cancelAllOperations;        //取消队列中所有的任务

- (void)waitUntilAllOperationsAreFinished;    //阻塞当前线程直到此队列中的所有任务执行完毕

[queue setSuspended:YES];          // 暂停queue

[queue setSuspended:NO];          // 继续queue

线程同步

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

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

@synchronized(self) {//需要执行的代码块}

延迟执行

所谓延迟执行就是延时一段时间再执行某段代码。下面说一些常用方法。

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

[selfperformSelector:@selector(run:) withObject:@"abc"afterDelay:3];

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


NSThread

[selfperformSelectorOnMainThread:@selector(run) withObject:nilwaitUntilDone:NO];

GCD

dispatch_async(dispatch_get_main_queue(), ^{});

NSOperationQueue

[[NSOperationQueuemainQueue] addOperationWithBlock:^{}];

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

推荐阅读更多精彩内容