IOS开发之 -- 线程初识
对于开发者来说,多线程永远有这一层神秘的色彩,似乎是一到迈步过去的坎,在同步、异步、串行、并行、死锁这几个名字当中,逐渐的放弃治疗,下面就多线程,谈一下自己的认识,理解的肯定不全面,只是一些简单的皮毛,特在此记录下,哪位大神看到了,还希望能多多指正!
首先:什么是线程,线程和进程的区别和联系
一个程序至少要有进城,一个进程至少要有一个线程.
进程:资源分配的最小独立单元,进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程:进程下的一个分支,是进程的实体,是CPU调度和分派的基本单元,它是比进程更小的能独立运行的基本单位,线程自己基本不拥有系统资源,只拥有一点在运行中必不可少的资源(程序计数器、一组寄存器、栈),但是它可与同属一个进程的其他线程共享进程所拥有的全部资源。
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些
什么是多线程编程?
NSThread
:当需要进行一些耗时操作时会把耗时的操作放到线程中。线程同步:多个线程同时访问一个数据会出问题,NSlock、线程同步块、@synchronized(self){}。NSOperationQueue操作队列
(不需考虑线程同步问题)。编程的重点都放在main里面,NSInvocationOperation
、BSBlockOperation
、自定义Operation。创建一个操作绑定相应的方法,当把操作添加到操作队列中时,操作绑定的方法就会自动执行了,当把操作添加到操作队列中时,默认会调用main方法。GCD(
`Grand Central Dispatch
)宏大的中央调度,串行队列、并发队列、主线程队列;同步和异步:同步指第一个任务不执行完,不会开始第二个,异步是不管第一个有没有执行完,都开始第二个。
串行和并行:串行是多个任务按一定顺序执行,并行是多个任务同时执行;
代码是在分线程执行,在主线程嘟列中刷新UI。
多线程编程是防止主线程堵塞、增加运行效率的最佳方法。
Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法;
一个NSOperationQueue操作队列,相当于一个线程管理器,而非一个线程,因为你可以设置这个线程管理器内可以并行运行的线程数量等。
多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。
iPhoneOS下的主线程的堆栈大小是1M。第二个线程开始就是512KB,并且该值不能通过编译器开关或线程API函数来更改,只有主线程有直接修改UI的能力。
定时器与线程的区别;
定时器;可以执行多次,默认在主线程中。
线程:只能执行一次。
GCD初始:
一条重要的准则
一般来说,我们使用GCD的最大目的是在新的线程中同时执行多个任务,这意味着我们需要两项条件:
能开启新的线程
任务可以同时执行
结合以上两个条件,也就等价“开启新线程的能力 + 任务同步执行的权利”,只有在满足能力与权利这两个条件的前提下,我们才可以在同时执行多个任务。
所有组合的特点:
各个组合下的代码执行:
//异步执行+并行队列
-(void)asynConcurrent
{
//并行队列
dispatch_queue_t two_queue = dispatch_queue_create("hero.hel.11223", DISPATCH_QUEUE_CONCURRENT); NSLog(@"---start---"); dispatch_async(two_queue, ^{
NSLog(@"任务一---%@",[NSThread currentThread]);
}); dispatch_async(two_queue, ^{
NSLog(@"任务二---%@",[NSThread currentThread]);
}); dispatch_async(two_queue, ^{
NSLog(@"任务三---%@",[NSThread currentThread]);
}); NSLog(@"--end---");
}
打印结果:
-- ::34.500 线程的练习[:] ---start---
-- ::34.501 线程的练习[:] --end---
-- ::34.501 线程的练习[:] 任务一---<NSThread: 0x618000078480>{number = , name = (null)}
-- ::34.501 线程的练习[:] 任务二---<NSThread: 0x60000007d100>{number = , name = (null)}
-- ::34.501 线程的练习[:] 任务三---<NSThread: 0x6180000728c0>{number = , name = (null)} 异步执行意味着:
1、可以开启新的线程
2、任务可以先绕过不执行,回头再来执行 并行队列意味着:
1、任务之间不需要排队,且具有同时被执行的“权利”
两者组合后的结果:
1、开了三个新线程
2、函数在执行时,先打印了start和end,再回头执行这三个任务
3、这三个任务是同时执行,没有先后
//同步执行+串行队列
-(void)synSerial
{
//串行队列
dispatch_queue_t one_queue = dispatch_queue_create("hero.hgl.112233", DISPATCH_QUEUE_SERIAL); NSLog(@"--开始--"); dispatch_sync(one_queue, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
}); dispatch_sync(one_queue, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
}); dispatch_sync(one_queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
}); NSLog(@"--结束--");
}
打印结果:
-- ::34.502 线程的练习[:] --开始--
-- ::34.505 线程的练习[:] 任务1---<NSThread: 0x618000075340>{number = , name = main}
-- ::34.505 线程的练习[:] 任务2---<NSThread: 0x618000075340>{number = , name = main}
-- ::34.506 线程的练习[:] 任务3---<NSThread: 0x618000075340>{number = , name = main}
-- ::34.507 线程的练习[:] --结束-- 这里的执行原理和步骤图跟“同步执行+并发队列”是一样的,只要是同步执行就没法开启新的线程,所以多个任务之间也一样只能按顺序来执行
//异步执行+串行队列
-(void)asynSerial
{
//串行队列
dispatch_queue_t h_queue = dispatch_queue_create("hero112233.com", DISPATCH_QUEUE_SERIAL); NSLog(@"开始了----"); dispatch_async(h_queue, ^{
NSLog(@"a计划 -- %@", [NSThread currentThread]);
}); dispatch_async(h_queue, ^{
NSLog(@"b计划 -- %@", [NSThread currentThread]);
}); dispatch_async(h_queue, ^{
NSLog(@"c计划 -- %@", [NSThread currentThread]);
}); NSLog(@"--结束了---");
}
打印结果:
2017-04-06 15:35:37.916 线程的练习[2376:173399] 开始了----
2017-04-06 15:35:37.916 线程的练习[2376:173399] --结束了---
2017-04-06 15:35:37.916 线程的练习[2376:173459] a计划 -- <NSThread: 0x600000075d00>{number = 3, name = (null)}
2017-04-06 15:35:37.917 线程的练习[2376:173459] b计划 -- <NSThread: 0x600000075d00>{number = 3, name = (null)}
2017-04-06 15:35:37.917 线程的练习[2376:173459] c计划 -- <NSThread: 0x600000075d00>{number = 3, name = (null)}
异步执行意味着:
1、可以开启新的线程
2、任务可以先绕过不执行,回头再来执行
串行队列意味着:
1、任务必须按添加进队列的顺序挨个执行
两者组合后的结果:
1、开启了一个新的子线程
2、函数在执行时,先打印了开始和结束,再回头执行这三个任务
3、三个任务是按顺序执行的,所以打印结果是“任务a-->任务b-->任务c”
//同步执行+并行队列
-(void)synConcurrent
{
//并行队列
dispatch_queue_t r_queue = dispatch_queue_create("aaaa.com", DISPATCH_QUEUE_CONCURRENT); NSLog(@"@@@开始了"); dispatch_sync(r_queue, ^{
NSLog(@"a1计划 -- %@", [NSThread currentThread]);
}); dispatch_sync(r_queue, ^{
NSLog(@"a2计划 -- %@", [NSThread currentThread]);
}); dispatch_sync(r_queue, ^{
NSLog(@"a3计划 -- %@", [NSThread currentThread]);
}); NSLog(@"@@@@结束了");
}
打印结果:
2017-04-06 15:40:24.100 线程的练习[2410:175780] @@@开始了
2017-04-06 15:40:24.135 线程的练习[2410:175780] a1计划 -- <NSThread: 0x6000000734c0>{number = 1, name = main}
2017-04-06 15:40:24.136 线程的练习[2410:175780] a2计划 -- <NSThread: 0x6000000734c0>{number = 1, name = main}
2017-04-06 15:40:24.136 线程的练习[2410:175780] a3计划 -- <NSThread: 0x6000000734c0>{number = 1, name = main}
2017-04-06 15:40:24.136 线程的练习[2410:175780] @@@@结束了 同步执行意味着:
1、不能开启新的线程
2、任务创建后必须执行完才能往下走
并行队列意味着:
1、任务必须按添加进队列的顺序挨个执行
两者结合:
1、所有任务都只能在主线程中执行
2、函数在执行时,必须按照代码的书写顺序一行一行的执行完才能继续
注意:
在这里即便是并行队列,任务可以同时执行,但是由于只存在一个主线程,所以没法把任务分发到不同的线程去同步处理,期结果就是只能在主线程里
按顺序挨个执行了
//异步执行+主队列
-(void)asynmainQueue
{
//主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue(); NSLog(@"@@@start"); dispatch_async(mainQueue, ^{
NSLog(@"a11计划 -- %@", [NSThread currentThread]);
}); dispatch_async(mainQueue, ^{
NSLog(@"a22计划 -- %@", [NSThread currentThread]);
}); dispatch_async(mainQueue, ^{
NSLog(@"a33计划 -- %@", [NSThread currentThread]);
}); NSLog(@"@@@end");
}
打印结果:
-- ::34.532 线程的练习[:] @@@start
-- ::34.532 线程的练习[:] @@@end
-- ::34.708 线程的练习[:] a11计划 -- <NSThread: 0x618000075340>{number = , name = main}
-- ::34.709 线程的练习[:] a22计划 -- <NSThread: 0x618000075340>{number = , name = main}
-- ::34.709 线程的练习[:] a33计划 -- <NSThread: 0x618000075340>{number = , name = main} 异步执行意味着:
1、可以开启新的线程
2、任务可以先绕过去不执行,回头再来执行
主队列和串行队列的区别:
1、队列中的任务一样要按顺序执行
2、主队列中的任务必须在主线程中执行,不允许在子线程中执行
//同步执行+主队列 -->死锁
-(void)synmainQueue
{
//主队列
dispatch_queue_t hmainQueue = dispatch_get_main_queue(); NSLog(@"@@@start"); dispatch_sync(hmainQueue, ^{
NSLog(@"a11计划 -- %@", [NSThread currentThread]);
}); dispatch_sync(hmainQueue, ^{
NSLog(@"a22计划 -- %@", [NSThread currentThread]);
}); dispatch_sync(hmainQueue, ^{
NSLog(@"a33计划 -- %@", [NSThread currentThread]);
}); NSLog(@"@@@end");
}
打印结果:
-- ::06.447 线程的练习[:] @@@start 解释:
1、主队列中的任务必须按顺序挨个执行
2、任务1要等主线程有空的时候(即主队列中的所有任务执行完)才能执行
3、主线程要执行完“end”的任务才有空
4、a11计划和end两个任务互相等等,造成死锁
IOS开发之 -- 线程初识的更多相关文章
- iOS开发之线程间的MachPort通信与子线程中的Notification转发
如题,今天的博客我们就来记录一下iOS开发中使用MachPort来实现线程间的通信,然后使用该知识点来转发子线程中所发出的Notification.简单的说,MachPort的工作方式其实是将NSMa ...
- iOS开发系列-线程同步技术
概述 多线程的本质就是CPU轮流随机分配给每条线程时间片资源执行任务,看起来多条线程同时执行任务. 多条线程同时访问同一块资源,比如操作同一个对象.统一变量.同一个文件,就会引发数据错乱和数据安全的问 ...
- iOS开发之线程组解决请求多个接口数据,完成后,再刷新界面
1.多任务请求接口,完成后,在刷新数据,常用方法 2018年07月18日 16:34:38 hbblzjy 阅读数:1382 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...
- iOS开发开辟线程总结--NSThread
1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...
- iOS开发多线程-线程间通讯
一.NSThread 线程间的通讯 - (void)demoAboutNSThread { NSLog(@"demoAboutNSThread %@", [NSThread cur ...
- iOS开发系列-线程状态
概述 线程从创建到销毁中间存在很多种状态. 线程的状态 通过NSThread创建一条线程,开发者需要负责线程的创建和执行,线程的销毁由系统决定.创建一个继承NSThread的FMThread类,重写d ...
- iOS开发:(线程篇-上)线程和进程
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- iOS开发多线程篇—线程安全
iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
- iOS开发多线程篇—创建线程
iOS开发多线程篇—创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] in ...
随机推荐
- 从cocos2dx到cocos2dhtml5的不同之处
首先cocos2dhtml5使用javascript编程, 严格区分大写和小写. 1.新建cocos2dhtml5项目. 直接复制引擎自带的helloworld.改一下目录名字就可以. 2.新增js文 ...
- 【VBA编程】08.数组
[数组简介]数组其实就是一组相同类型的数据的有序集合,其形象表示就像线性表.在存储数据的时候,首先在内存中分配一个连续的存储空间,将各个元素按顺序存放在连续的存储单元格中.[定义静态数组]Dim 数据 ...
- SpringMVC学习小结
配置web.xml: <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-cl ...
- Linux修改时间的方法
http://www.blogjava.net/itvincent/archive/2007/08/03/134242.html修改linux的时间可以使用date指令 在命令行输入: date 显示 ...
- swiper动态加载数据滑动失效,ajax执行后swiper.js的效果消失问题
使用swiper.js做一些动效时,如果进行了ajax,并且重新把DOM写入到HTML代码中,会导致swiper.js的特效消失的问题.原因是ajax加载后,原先new 的Swiper对象,不认识新来 ...
- DataURL与File,Blob,canvas对象之间的互相转换的Javascript (未完)
canvas转换为dataURL (从canvas获取dataURL) var dataurl = canvas.toDataURL('image/png'); var dataurl2 = canv ...
- composer自动加载一个文件后必须执行命令composer dump-autoload
"autoload": { "classmap": [ "database" ], "psr-4": { "A ...
- 저장소system.runtime.remoting.messaging.callcontext
https://msdn.microsoft.com/ko-kr/library/system.runtime.remoting.messaging.callcontext(v=vs.110).asp ...
- [个人开发人员赚钱九]做一个日收入10元的APP!
[导语]尽管讲了非常多个人开发人员的文章.但新手开发人员怎样赚自己的第一个10块钱.确是最难的事情.群里有人说都不知道干什么app赚钱.全然没有想法.而且常常问我有什么高速赚钱的方法.我仅仅能遗憾地 ...
- AES加密在windows与linux平台下显示结果不同,解决方案
现象描述: 在 windows 操作系统下加解密正常,但部署到 linux 环境中相同的输入加密结果不正确,并且每次运行返回的结果都不同.也就是说在windows下加解密都正常,一但部署到linux下 ...