多线程(NSThread)

线程与进程的关系:

1>进程和应用程序的关系:进程为应用程序开辟内存空间

2>程和应用程序的关系:线程执行应用程序中的代码

3>进程和线程的关系:进程是由线程组成的,一个进程至少包含一条线程(主线程)

runloop和线程有什么关系?

1.每一个线程中都⼀个runloop,只有主线的的runloop默认是开启的,其他线程的runloop是默认没有开启的

2.可以通过CFRunLoopRun()函数来开启⼀一个事件循环

3.看SDWebImage源码的时候⻅到有这么⽤过.

runloop的model作用是什么?

model主要是用来指定时间在运行循环中的优先级的 苹果公开提供的Mode有两个:

kCFRunLoopDefaultMode

kCFRunLoopCommonModes

如果我们把一个NSTimer对象以kCFRunLoopDefaultMode添加到主运行循环中的时候,当一直 有用户事件处理的时候,NSTimer将不再被调度 如果我们把一个NSTimer对象以kCFRunLoopCommonModes添加到主运行循环中的时候,当一 直有用户事件处理的时候,NSTimer还能正常的调度,互不影响.

runloop内部的实现:

1.他是一个死循环

2.如果事件队列中存放在事件,那就取出事件,执⾏行相关代码

3.如果没有事件,就挂起,等有事件了,⽴立即唤醒事件循环,开始执⾏

在多线程的中使用block:

block在管理子线程以及线程的创建个销毁是由队列负责的,直接在block中使用self没有关系,不会造成循环引用

多线程:就是多条线程,也指并发编程

多线程的底层是通过Mach实现的

开发多线程的多种方案:

1>C语言POSIX接口:#include

2>OC的NSThread

3>C语言的CGD接口( 性能最好 , 代码最精简 )

4>OC的NSOperationn和NSOperationQueue (基于CGD)

线程间通信:

//最后一个参数:是否等待调用方法执行结束!

<1>[selfperformSelectorOnMainThread:@selector(setImageWithImage:) withObject:nilwaitUntilDone:YES];

<2>[selfperformSelector:@selector(setImageWithImage:) onThread:[NSThread mainThread] withObject:nilwaitUntilDone:YES];

3>经典组合:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{

//在这里执行耗时操作

dispatch_async(dispatch_get_main_queue(), ^{

//在这里更新UI界面

});

});

一般通信会使用在子线程下载数据,做一些耗时操作,在主线程更新UI界面

使用NSThread开启线程的方式

//创建线程的几种方式

//1>直接创建一条子线程

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

//开启线程

[threadstart];

//获取主线程

[NSThreadmainThread];

//检测当前线程是否为主线程

NSLog(@"%d",[NSThreadisMainThread]);

//2获取当前线程

NSThread*currentThread = [NSThreadcurrentThread];

//判断当前线程的状态(线程所处的位置)

BOOLis = [currentThreadisMainThread];

//设置线程的名字

[currentThreadsetName:@"123"];

//3直接创建一条线程

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

//4开启一条隐式线程

[selfperformSelectorInBackground:@selector(run1)withObject:nil];

线程的生命周期:

新建一个线程->开启->等待CPU调度->执行任务/强制退出/异常->线程结束/死亡

注意:一旦线程死亡之后,就不会被调度,也就是不会再执行该线程中任务

线程的阻塞:

1>在开启线程之后,如果执行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥锁,都会导致线程阻塞blocked

2>在CPU调度线程后,线程中的任务正在执行 ,如果执行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥锁,都会导致线程阻塞blocked

线程之间资源共享问题:

同一个资源被多条线程同时访问的时候会造成数据信息错误的问题 例子:在不同的地方同一时间去ATM取钱,一个在存.一个在取

问题解决方案:

添加互斥锁

@synchronized(锁对象) {//需要锁定的代码}

注意:锁定1份代码只用1把锁,用多把锁是无效的

互斥锁的优缺点

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

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

互斥锁的使用前提:多条线程抢夺同一块资源

相关专业术语:线程同步

线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务)

互斥锁,就是使用了线程同步技术

添加互斥锁的技巧 :[[NSUserDefaultsstandardUserDefaults]synchronize];利用此行代码可以敲出@synchronized

同步函数(sync)和异步函数 (async)与 线程之间的关系:

1>同步函数 + 串行队列 : 没有开启新线程,串行执行任务

2>同步函数 + 并行队列 : 没有开启新线程,串行执行任务

3>同步函数 + 主队列 : 没有开启新线程  ,卡住主线程

总结:同步函数执行任何类型队列,都不会开启新线程;都是在当前线程执行任务,同步函数不具备开启新线程的能力

1>异步函数 + 串行队列 : 会开启一条新的线程,并且任务按顺序执行

2>异步函数 + 并行队列 : 会开启多条子线程,任务同时执行

3>同步函数 + 主队列 : 没有开启新线程,任务按顺序执行

注意:使用sync函数往当前串行队列添加任务,会卡住当前的串行队列.

GCD的队列(dispatch_queue_t)分哪两种类型?

串⾏行队列和并⾏行队列

队列决定了操作是在主线程执行还是子线程执行

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张 图片,然后在都下载完成后合成一张整图)

1.创建异步队列

2.创建dispatch_group_tdispatch_group_t  =dispatch_group_create();3.通过组来执⾏行异步下载任务

dispatch_group_async(dispatch_group_t, dispatch_queue_t, ^{

NSLog(@"下载图片");

});

4.等到所有任务完成

dispatch_group_wait(dispatch_group_t,DISPATCH_TIME_FOREVER);

5.合成图⽚

dispatch_barrier_async的作用是什么?

barrier:是障碍物的意思,在多个并⾏行任务中间,他就像是⼀一个隔离带,把前后的并⾏行任务分开.dispatch_barrier_async作⽤用是在并⾏行队列中,等待前⾯面操作并⾏行任务完成 在执⾏行dispatch_barrier_async中的任务 如果后⾯面还有并⾏行任务,会开始执⾏行后续的并⾏行任务

苹果为什么要废弃dispatch_get_current_queue?

容易误⽤用造成死锁

- (void)viewDidLoad {

[superviewDidLoad];

NSLog(@"1");

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"2");

});

NSLog(@"3");

}只能输出1,然后线程主线程锁死

有4个术语比较容易混淆:同步、异步、并发、串行

同步和异步主要影响:能不能开启新的线程

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

异步:在新的线程中执行任务,具备开启新线程的能力

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

并发:多个任务并发(同时)执行

串行:一个任务执行完毕后,再执行下一个任务

>同步函数:同步就是顺序依次执行,如果在子线程上就是在子线程处理,但是不会建立新线程

>只在主线程上操作

dispatch_sync(dispatch_get_main_queue()^{

})

1.1在主线程操作会遵循PIPE的队列顺序去操作

1.2但是这样资源一旦多了起来就会导致主线程堵塞

>同步并发处理

>什么是并发

并发是在同一条线程内开启多个队列一起处理,就比如你玩游戏在玩MMORPG的时候你打怪物的同时怪物也在攻击你,这就是并发.

dispatch_sync(dispatch_get_glodal_queue(0,0), ^{

//括号(0,0)是干嘛的?

//它是用来对队列任务进行一个优先级处理

//现在这个东西可以忽略不计

//当然有三个级别

//2:是是最高级别0:正常级别-2:最低级别

});同步函数的特性就是不会建立新线程,所以不会创建新线程会依次处理完

在队列上得所有任务,执行完毕进行一个结果返回.

>同步串行处理

>什么是串行

串行会创建一条新线程.但是会依次对任务进行一个操作处理

dispatch_sync(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{

});

其实串行队列和同步函数的是相同的原理,所以同步串行其实没什么用,但是也会用得到,比如控制程序在手机上面的用电量,多开线程耗电会增加,如果有这个需求可以使用同步串行

>异步函数

异步函数就是会并发执行,执行完成一个返回一个是无序的,具有开启新线程的功能

>只在主线程操作

dispatch_async(dispatch_get_main_queue()^{

})在主线程都是依次操作

>异步并发处理

dispatch_async(dispatch_get_glodal_queue(0,0),^{

});

异步并发:

1.多个任务在多条线程下同时进行

2.没有排队,无序,这样容易导致出错

>异步串行处理

dispatch_async(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{

});

异步串行:

1.多个任务在多条线程下同时进行

2.有序排队,等每一条有执行完在进行下一个任务的操作

同步操作/异步操作总结:

1.无论是异步同步在主线程上都是依次执行

2.同步操作会依次进行操作,异步操作则是无序执行

3.同步操作不会开启新线程,异步操作会开启新线程

4.异步并发容易出错,无序不排队,会导致数据丢失

5.异步串行,安全有序

6.同步并发,限制线程开启,但是依次执行

7.同步串行,其实两个作用都是相同的,但是由于同步不具备开启线程,所以还是依次执行,特殊情况下课考虑使用

并发队列的开启:

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

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

dispatch_queue_tdispatch_get_global_queue(

dispatch_queue_priority_tpriority,//队列的优先级

unsignedlongflags);//此参数暂时无用,用0即可

dispatch_queue_tqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//获得全局队列

全局并发队列的优先级

#define DISPATCH_QUEUE_PRIORITY_HIGH2//高

#define DISPATCH_QUEUE_PRIORITY_DEFAULT0//默认(中)

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)//低

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN//后台

串行队列的创建:

GCD中获得串行有2种途径

使用dispatch_queue_create函数创建串行队列

dispatch_queue_t

dispatch_queue_create(constchar*label,//队列名称

dispatch_queue_attr_tattr);//队列属性,一般用NULL即可

dispatch_queue_tqueue =dispatch_queue_create("cn.itcast.queue",NULL);//创建

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

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

主队列是GCD自带的一种特殊的串行队列

放在主队列中的任务,都会放到主线程中执行

使用dispatch_get_main_queue()获得主队列

dispatch_queue_tqueue =dispatch_get_main_queue();

延时执行:

iOS常见的延时执行有2种方式

1>调用NSObject的方法

[selfperformSelector:@selector(run)withObject:nilafterDelay:2.0];

// 2秒后再调用self的run方法

2>使用GCD函数

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

// 2秒后执行这里的代码...在哪个线程执行,跟队列类型有关

});

GCD使用的在单例对象

//一次性代码,(单例的创建)

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

//在这里创建只需要所一个的对象和对象属性的配置信息

});

GCD中队列组的使用

//队列组的使用

dispatch_group_tgroup =dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

//执行一个耗时操作

});

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

//执行另外一个耗时操作

});

dispatch_group_notify(group,dispatch_get_main_queue(), ^{

//回到主线程执行的操作

});

GCD中两个特殊的队列

//创建主队列

dispatch_queue_tmainQueue =dispatch_get_main_queue();

//创建全局并发队列

dispatch_queue_tglobalQueue =dispatch_get_global_queue(0,0);

GCD使用有两个步骤:

1>将任务添加到队列中;

2>选择同步还是异步的方式执行任务.

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

推荐阅读更多精彩内容