NSThread使用&GCD使用&&NSOperation使用&&线程安全

纯属娱乐

0.0 简介

(1) 进程和线程基本概念【查看活动监视器】

> 什么是进程

a、是指在系统中正在运行的一个应用程序;

b、每个进程之间是独立的,每个进程运行在其专用且受保护的内存空间;

> 什么是线程

a、一个进程想要执行任务,必须得有线程(每个进程至少要有一条线程);

b、线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行;

> 线程的串行

a、一个线程中任务的执行是串行的(在一个线程中执行多个任务,那么只能一个一个的按顺序执行,在同一时间内,一个线程只能执行一个任务);

> 线程的并行

a、一个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务;

【例如在一个线程中下载3个文件是串行;同时开启3条线程分别下载3个文件是并行】

> 多线程的原理

a、单核CPU:同一时间,CPU只能处理一条线程,只有一条线程在工作(执行);多线程并发(同时)执行,其实是CPU快速的在多条线程之间调度(切换/轮询);CPU调度线程的时间足够快,看到的多线程并发(同时)执行的假象;

b、多核CPU

> 多线程优缺点

a、优点:适当提高程序的执行效率;适当提高资源利用率(CPU/内存利用率);

b、缺点:开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能;

> iOS创建线程的方式

pthread/NSThread/GCD/NSOperation

pthread用法

IPHONE4: 512m

安卓: 2G

安卓(多进程): Linux + JAVA虚拟机 + 应用程序

(QQ100M + 微信100M + UC浏览器100M + 游戏500M + 系统1G)

苹果(多任务): 512M只有一个人用

1,NSThread

a,显示创建alloc init会创建新的线程,需要手动开启start,线程可以设置名字name。方法运行结束,线程结束。

2,b,隐式创建新线程,自动开启

3,YES&&NO

1,YES即等待线程@selector操作做完才继续执行

2,NO即不等待线程线程操作完成

此图请自动忽略水印

4,线程的生命周期:

             1,alloc+init:即创建对象,在运行的内存中;

            2,start:即线程为就绪态 (万事具备,等待CPU);

            3,当CPU调度当前线程:即线程为运行态;

            4当CPU调度其他线程:即线程又回到就绪态;

            5,当线程调用了sleep、等待同步锁:即线程为阻塞态;

            6,当线程中sleep完、得到同步锁:即线程变为就绪态;

             7,当线程任务执行完成/异常/强制退出:即线程为死亡态;

5,线程安全 没有加锁,访问的数据不是想要的

6,线程安全 没有加锁,访问的数据不是想要的

7,线程安全 使用@synchronized加锁,访问的数据是想要的

8,线程安全 使用NSLock加锁,访问的数据是想要的

9,GCD简介

> 什么是GCD

a、全称是Grand Center Dispatch,即中枢调度器;

b、纯C语言,提供了非常多强大的函数;

> GCD的优势

a、GCD是苹果公司为多核的并行运算提出的解决方案;

b、GCD会自动利用更多的CPU内核(比如双核、四核);

c、GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程);

d、程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码;

> GCD的2个核心概念

a、任务:执行什么操作(执行下载、播放音乐等);

b、队列:用来存放任务;

> GCD的使用步骤

a、定制任务[确定想要做的事情];

b、将任务添加到队列中[GCD会自动将队列中的任务取出,放到对应线程中执行;另外任务的取出是遵循队列的FIFO原则:先进先出];

> GCD基本使用

a、GCD中的2个用来执行任务的函数

// 同步方式执行任务[queue队列,block任务]

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

// 异步方式执行任务[queue队列,block任务]

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

b、GCD同步和异步的区别

- 同步:只能在当前线程中执行任务,不具备开启新线程的能力;

- 异步:可以在新的线程中执行任务,具备可启新线程的能力;

[具备开启线程的能力,但不代表一定会开启线程!!!]

c、GCD队列的两大类型

- 并发队列

多个任务并发(同时)执行(自动开启多个线程同时执行任务);

并发功能只有在异步(dispatch_async)函数下才有效;

- 串行队列

多个任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务);

d、容易混淆的术语[同步、异步、并发、串行]

- 同步和异步主要影响:具不具备开启新的线程 (并不代表一定会开线程!);

- 并行和串行主要影响:任务的执行方式;

e、并行队列

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

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

dispatch_queue_t dispatch_get_global_queue(long identifier, // 队列的优先级

unsigned long flags); // 参数保留,用0即可

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列

- 全局并发队列的优先级

DISPATCH_QUEUE_PRIORITY_HIGH      高

DISPATCH_QUEUE_PRIORITY_DEFAULT    默认(中)

DISPATCH_QUEUE_PRIORITY_LOW        低

DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台

f、串行队列

- 使用dispatch_queue_create函数创建串行队列

- 使用dispatch_get_main_queue()获得主队列(跟主线程相关的队列,用于线程间通信)

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

GCD、延时执行

/** 方式1,这种延时操作是不可取的,因为延时操作是在主线程,即会卡住主线程,如果sleep在其他线程则也会卡住对应线程*/

  方式1   延时3秒[NSThread sleepForTimeInterval:3];

  方式2   定制好任务后,不会卡住当前线程

[self performSelector:@selector(downloadImage) withObject:nil afterDelay:3];

 方式3  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

NSLog(@"图片下载");

});

> GCD中线程间的通信

communication

> GCD一次性代码只执行一次

写单例

10,总结

11,异步+并发 开启新线程 多个任务同时执行

12,异步+串行 开启新线程 任务依次同时执行

13,同步+并发 不开启新线程 任务依次执行

14,同步+串行 不开新线程 任务依次执行

15,异步+主队列 不开启新线程 任务依次执行(主队列任务是一次执行的,并且是异步)

16,同步+主队列 不开启新线程 任务依次执行(坚决反对使用这个,容易卡)

17,pthread

18,NSOperation(基于GCD封装)

> NSOperation和NSOperationQueue实现多线程的具体步骤:

a、将需要执行的操作封装到一个NSOperation对象中;

b、然后将NSOperation对象添加到NSOperationQueue中;

c、系统会自动将NSOperationQueue中的NSOperation取出来;

d、将取出来的NSOperation封装的操作放到一条新线程中执行;

【系统会自动处理,不用管多少条线程】

> NSOperation的基本使用

a、NSOperation是抽象类,不具备封装操作的能力,必须使用它的子类;

b、使用NSOperation子类的方式有3种

- 1,NSInvocationOperation

- 2,NSBlockOperation

- 3,自定义子类继承NSOperation,实现内部相应的方法

> NSInvocationOperation

 创建操作

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

> NSBlockOperation

没有添加到队列中,直接调用operation的start方法

当任务个数为一的时候,就是同步执行;

当任务个数大于一的时候,就会异步执行;

手动开启 (没有添加到队列中,就需要手动开启)

[operation start];

添加到队列中 [自动异步执行]

[queue addOperation:operation];

> NSOperationQueue

1、创建一个队列(非主队列)

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

2、任务任务

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{

NSLog(@"operation1      下载图片---%@",[NSThread currentThread]);

}];

[operation1 addExecutionBlock:^{

NSLog(@"operation2      下载图片---%@",[NSThread currentThread]);

}];

3、添加到队列中(多个任务会自动异步执行任务,并发)

[queue addOperation:operation1];

// 更为简单的写法  自动异步执行任务,并发

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

[queue addOperationWithBlock:^{

NSLog(@"operation3      下载图片---%@",[NSThread currentThread]);

}];

设置最大并发数[这可以更好的保证程序的性能],即控制并发执行最大线程数量,以节省内存空间

queue.maxConcurrentOperationCount = 2;

a、NSOperation之间可以设置依赖来保证执行顺序(注意不能相互依赖);

添加依赖 (和添加到队列的先后顺序无关)

[operationC addDependency:operationB];

[operationB addDependency:operationA];

b、可以在不同queue中的NSOperation之间创建依赖;

> 线程间通信 回到主线程设置显示


> 队列的取消、暂停、恢复

a、取消队列的所有操作

- (void)cancelAllOperations; 【在内存警告的时候可以添加上该方法】

[也可以调用NSOperation的- (void)cancel方法取消单个操作]

b、暂停和恢复队列

- (void)SetSuspended:(BOOL)b; 【YES表示暂停队列,NO表示恢复队列】

[滚动视图(注意表格视图也是继承自UIScrollView的)性能优化中可以使用到,开始拖动的时候暂停队列下载,拖动结束后恢复队列]

接收到内存警告

- (void)didReceiveMemoryWarning{

[super didReceiveMemoryWarning];

// 取消队列操作

}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{

//开始拖动,暂停队列操作

}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

// 结束拖动,恢复队列操作

}

(5) 线程安全(在GCD以后,已经帮我们处理了这些问题)

 线程安全问题

实例:3个窗口卖票

> 3个窗口同时卖票,即多条线程访问同一资源;

> 线程哪个先调用是不确定的,先调度谁是CPU的事;

> 当线程任务执行完成,线程为死亡态(如果是没有while循环,但第二次点击的时候程序就崩溃);

> 多线程的安全隐患

a、资源共享(资源抢占):一块资源可能会被多个线程共享(即多个线程可能访问一个资源);

(当多个线程访问同一块资源时,很容易引发数据错乱和数据安全的问题)[例如一个线程取钱,一个线程存钱;例如卖票,多个窗口卖票即多条线程卖]

> 互斥锁的使用

a、互斥锁方式一:@synchronized(锁对象){//需要加锁的代码}

// 锁定一份代码只用一把锁,用多把锁是无效的;

b、互斥锁方式二:

/** 1、互斥锁的初始化*/

_myLock = [[NSLock alloc] init];

// 2、加锁方式2

[_myLock lock];

// 需要加锁的代码

// 3、解锁

[_myLock unlock];

> 互斥锁的优缺点

优点:能有效防止因多线程抢夺资源造成的数据安全问题;

缺点:需要消耗大量CPU资源;

> 互斥锁使用的前提:多条线程抢占同一资源;

> 单例的线程安全

> 数据库操作的线程安全

nonatomic(atomic):指定set、get方法是否原子操作。原子操作,主要指是否线程安全。如果使用atomic那么set、get方法都是线程安全的--- 当一个线程进入get、set方法之后,其他线程无法进入该set、get方法,那么久避免多线程并发破坏数据完整性,atomic是默认值。虽然atomic可以保证对象数据的完整性,但atomic线程安全会造成性能下降(因为会导致其他线程的阻塞)。因此,大多数单线程环境下,都是使用nonatomic来提高set、get方法的访问性能;

线程注意点:

1、不要同时开太多线程(1~3条线程即可,不要超过5条);

2、线程概念:

主线程:UI线程,显示、刷新UI界面,处理UI控件事件;

子线程:后台线程,异步线程;

3、不要把耗时操作放在主线程,要放在子线程中执行;

19.GCD使用

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

推荐阅读更多精彩内容