7.多线程

  • GCD(使用最多)
  • NSOperation/NSOperationQueue(AFNetworking源码中所有网络请求任务都封装到NSOperation,提交到operationQueue中,SDWebImage也会涉及)
  • NSThread(实现常驻线程)
  • 线程同步、资源共享(在我们实际运用多线程运用技术过程中,所产生或者引发的线程同步、资源共享问题)
  • 互斥锁、自旋锁、递归锁等相关锁的一些技术内容

NSOperation

需要结合NSOperationQueue共同实现多线程

NSOperation方式去实现多线程技术方案,它的优势和特点?

1.可以添加任务依赖( addDependency/removeDependency 方法为响应的任务添加/移除依赖)  是GCD和NSThread不具备的

2.可以控制NSOperation任务的执行状态(可以重写对应的方法来实现对应状态的控制)

3.可以控制最大并发量     _queue.maxConcurrentOperationCount   设置为1,就相当于串行的任务执行方式。

任务执行状态控制

isReady 当前任务是否处于就绪状态

isExecuting 当前任务是否处于正在执行中状态

isFinished 当前任务是否已执行完毕

isCancelled 当前任务是否已取消

下面看它是如何控制状态的

1.如果只重写了NSOperation的main方法,底层会为我们控制变更任务执行完成状态,以及任务退出(后续线程的退出和NSOperation的退出)

2.如果重写了NSOperation的start方法,需要我们自行控制任务状态,在合适的时机去修改对应的isFinished等

  • 查看NSOperation的start方法源码,理解上面两点
    start方法内,首先创造一个自动释放池,然后获取线程优先级
    做一系列的状态异常判断,然后判断当前状态是否isExecuting
    如果不是,那么我们手动变成isExecuting,然后判断当前任务是否有被取消
    若未被取消就调用NSOperation的main方法
    再之后,调用NSOperation的finish方法。finish 方法中:在内部通过KVO的方式去变更isExecuting状态为isFinished状态
    之后调用自动释放池的release

所以系统是在start方法里面为我们维护了任务状态的变更,若重写start,则没人帮我们维护了,只能自己手动维护

系统是怎样移除一个isFinished = YES的NSoperation的?
通过上面源码知道,是通过KVO方式来移除NSOperationQueue中的NSOperation的

NSThread

常用它结合RunLoop一起实现常驻线程

当我们创建一个NSThread后,会手动调用start()方法来启动线程,那么它的内部实现机制是什么呢?

  • start()内部会创建pthread线程,同时指定这个线程的启动函数,
    在启动函数中,通知观察者当前线程已经启动,设置线程名称,然后会调用NSThread的main()函数,
    之后再调用线程关闭函数来关闭线程
  • 如果main里面什么都不做,那么这个线程启动后,执行完一段逻辑就退出了,
    如果我们想实现常驻线程,就需要在main里面去做一个Runloop的循环
  • 下面看系统关于main的实现是什么,main内部先会做一个异常判断,
    之后只有这一句调用[_target performSelector:_selector withObject:_arg], 会执行我们在创建NSThread时候所指定的选择器,也就是下图中的runRequest方法,就可以让我们在外部手动维护一个事件循环,进而实现常驻线程了

锁(线程安全问题)
例如卖票系统,100张票,好几个票点同时卖,数据就不对了
造成这个的原因是多线程的资源抢夺

还有一个情况,就是你在查找数据库的过程中,又对数据库进行增删改查了,也是线程之间的资源抢夺问题
为了解决这种问题,需要加锁来解决

在iOS当中都有哪些锁机制?

自旋锁和互斥锁的区别:
当发现有线程在操作任务时
自旋锁(OSSpinLock)一直在转,忙等,一直问你做完了没有,等线程出来后它就会立刻进去执行,适合代码量较小,耗时较小的互斥锁会打盹,等线程出来后,会先醒盹,然后再执行读写锁:多读单写,允许多条线程读,但只允许一条线程写,写影响读,读不影响写
例如很多地方都能调用set方法例如self.name,可以在set里面加一把互斥锁,保证在同一时间只有一条线程写入,其他线程等待
读的时候不加锁,随便读- (void)setName:(NSString*)name{
synchronized(self){
_name = name;
}
}常见的几种锁
1.互斥锁 @synchronized(self){里面写需要上锁的代码},一般在创建单例对象的时候使用,来保证多线程情况下创建的对象是唯一的互斥锁分递归锁和非递归锁,这是递归锁,非递归就是当你重复访问资源时会崩溃
2. atomic原子性,也是自旋锁
3. OSSpinLock自旋锁
4. NSLock
5. NSRecursiveLock递归锁
6. dispatch_semaphore_t信号量
1. @synchronized
一般在创建单例对象的时候使用,来保证多线程情况下创建的对象是唯一的2. atomic
修饰属性的关键字,可以对被修饰对象进行原子操作(不负责使用,意思是赋值操作可以保证线程安全,但其他操作例如增删改不能保证线程安全,需要我们做额外的线程保护)
虽然是线程安全的,但因为是自旋锁,一直忙等,会消耗大量的资源3. OSSpinLock自旋锁: 尽量不要用,会产生一个优先级的问题,相对不再安全了
专门用于轻量级的数据访问,简单的int值,对引用计数进行+1-1操作
循环等待访问,并不释放当前资源,类似于一个while循环,一直在访问能不能获得当前这个锁,如果不能获得,就继续循环,直到有一次能获得到这个锁,才会停止这个循环
如果第一次获得到了,后续线程再想获得这个锁,是获取不到的,它会释放所持有的当前资源,然后对自己进行一个阻塞行为
4. NSLock
最经常用的,一般用来解决线程同步问题,lock是加锁,unlock是解锁,必须成对出现,但是可能会造成死锁
5. NSRecursiveLock递归锁
可以解决上面问题,它的特性是可以重入

NSLock  iOS中对于资源抢占的问题可以使用同步锁NSLock来解决,使用时把需要加锁的代码(以后暂时称这段代码为”加锁代码“)放到NSLock的lock和unlock之间,一个线程A进入加锁代码之后由于已经加锁,另一个线程B就无法访问,只有等待前一个线程A执行完加锁代码后解锁,B线程才能访问加锁代码。

NSRecursiveLock :递归锁,有时候“加锁代码”中存在递归调用,递归开始前加锁,递归调用开始后会重复执行此方法以至于反复执行加锁代码最终造成死锁,这个时候可以使用递归锁来解决。使用递归锁可以在一个线程中反复获取锁而不造成死锁,这个过程中会记录获取锁和释放锁的次数,只有最后两者平衡锁才被最终释放。

6. dispatch_semaphore_t信号量是持有计数的信号。类似于过高速路收费站的栏杆。可以通过时,打开栏杆,不可以通过时,关闭栏杆,计数为0时等待,不可通过。计数为1或大于1时,计数减1且不等待,可通过。也是用来实现线程同步,包括对共享资源互斥访问的一个信号量机制信号量的使用前提是:想清楚你需要处理哪个线程等待(阻塞),又要哪个线程继续执行,然后使用信号量。注意: 信号量可以设置线程的并发量
若信号量设置并发线程为1,也不会出现资源抢夺,因为每次只出来一条线程


相关函数

dispatch_semaphore_create(1)

创建一个Semaphore并初始化信号的总量

函数内部创建了一个结构体Semaphore,里面一个是信号量的值,第二个是线程列表

dispatch_semaphore_wait(semaphone,DISPATCH_TIME_FOREVER)
可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。,参数(要等待的信号量是哪个,等待时长)
对value值进行-1,-1之后若小于0,意味着当前没有资源可以访问,或者说无法获取这个信号量,于是当前获取信号量的这个线程会主动把自己阻塞在S.List当中

dispatch_semaphore_signal(semaphore)
发送一个信号,让信号总量加1

总结:
怎样利用GCD实现多读单写呢(怎么实现一个多读单写的模型)?

通过栅栏异步调用的方式,分配写操作到并发队列当中。

iOS系统为我们提供几种多线程技术各自的特点是怎样的?
主要提供了三种多线程技术,分别为GCD、NSOperation和NSOperationQueue、NSThread。
GCD用来实现一些简单的线程同步、子线程的分派、多读单写的解决。
NSOperation和NSOperationQueue:像AFNetworking、SDWebImageView都会涉及到NSOperation,方便对任务的状态进行控制,以及添加、移除依赖。
NSThread实现常驻线程。

NSOperation对象在Finished后,是怎样从的queue当中移除掉的?
 内部通过KVO的方式来通知NSOperationQueue,然后达到对NSOperation对象进行移除的问题。

你都用过哪些锁,结合实际谈谈你是怎样使用的?

  • @synchronized:一般在创建单例对象的时候使用,来保证在多线程环境下被创建的对象是唯一的。
  • atomic:
    1. 修饰属性的关键字
    2. 对被修饰对象进行原子操作,即赋值时可以保证安全,但不负责使用。
  • OSSpinLock自旋锁:循环等待询问,不释放当前资源。用于轻量级数据访问,比如简单的int值 +1/-1操作。
  • NSRecursiveLock递归锁:可以重入,可以解决NSLock重入导致的死锁。
    ps:A方法调用B方法,两个方法都进行加锁操作的话,就涉及到锁重入的问题。就用递归锁来解决。
  • NSLock:解决线程同步问题,来保证各个线程互斥进入自己的临界区。
  • dispatch_semaphore_t信号量:create、wait、signal:调用信号量阻塞是一个主动行为。唤醒是一个被动行为。

iOS面试题(二十五)多线程 --NSOperation和NSOperationQueueNSThread锁机制相关推荐

  1. 面试题(二十五)设计模式

    1. 设计模式 1.1 说一说设计模式的六大原则 参考答案 单一职责原则 一个类,应当只有一个引起它变化的原因:即一个类应该只有一个职责. 就一个类而言,应该只专注于做一件事和仅有一个引起变化的原因, ...

  2. C语言试题二十五之编写一个函数float function(double h),函数的功能使对变量h中的值保留2位小数,并对第三位进行四舍五入(规定h中的值位正数)。

    1. 题目 编写一个函数float function(double h),函数的功能使对变量h中的值保留2位小数,并对第三位进行四舍五入(规定h中的值位正数). 2 .温馨提示 C语言试题汇总里可用于 ...

  3. java面试题二十九 多线程数据共享问题

    1 编一个程序,实现2个线程对 j 变量自增, 2个线程对 j 变量自减 2 代码如下 public class TestThread {public static void main(String[ ...

  4. java面试题二十六 多线程考题

  5. java面试题二十五 构造函数

  6. 二十五个软件测试经典面试题,你确定不收藏一波?

    二十五个软件测试经典面试题全在这里了,有兴趣的朋友建议收藏一波,或者留言交流! 1.在搜索引擎中输入汉字就可以解析到对应的域名,请问如何用LoadRunner进行测试? 建立测试计划,确定测试标准和测 ...

  7. osgEarth的Rex引擎原理分析(二十五)地形瓦片大小尺寸和LOD的关系

    目标:(十八)中的问题55 osgEarth::TerrainOption中_tileSize默认大小为17,LOD的默认范围为0-23,这两个值的关系是什么? 还有瓦片的像素尺寸_tilePixel ...

  8. 计算机基础设计第十五套,计算机基础试题第十五套

    计算机基础试题第十五套 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 文件夹创建:(5分)1. 在桌面上创建一个考生文件夹,以自己的& ...

  9. 打怪升级之小白的大数据之旅(二十五)<Java面向对象进阶之IO流三 其他常见流>

    打怪升级之小白的大数据之旅(二十五) Java面向对象进阶之IO流三 其他常见流 上次回顾 上一章,我们学习了常用的字节流与字符流,本章,我会将其他的一些常见的流进行分享,IO流很多,我介绍不完,就挑 ...

最新文章

  1. mysql单表多timestamp的current_timestamp设置问题
  2. pytest实战--参数化parametrize+前置fixture
  3. MIDP2.0引入了Push注册机制
  4. 操作系统之多线程编程—读者优先/写者优先详解
  5. java综合面试题_综合性18道面试官必问经典Java面试题!
  6. python-字符串转义符号
  7. 如何在bootstrap轮播中调整图像大小
  8. VS2010 小技巧
  9. VRTK之手柄事件监听以及重写StartUsing方法实现与物体的交互
  10. 冯偌依曼计算机的基本原理是,软件《计算机组成原理》试卷 A
  11. dockerfile中的env指令_Dockerfile中的ENV指令的具体使用详解
  12. 使用js进行登录表单验证
  13. 3ds Max 2012 简体中文版 带注册机32位64位
  14. html+字体有白色的重影+重影字体设置,LCD显示器显示模糊与字体有重影是什么原因...
  15. 聚焦云+人工智能,纳德拉宣布微软重大重组
  16. JS如何实现百度地图
  17. 简单阐述标准盒模型和怪异盒模型的差别和区别
  18. 如何录制英雄联盟 (LoL) 游戏视频
  19. java pdf转 图片
  20. Linux服务器开发,Posix API与网络协议栈

热门文章

  1. 《培根随笔》读书笔记(二)
  2. JavaScript-事件之onmousemove
  3. 优秀网页翻译:高精度 10MHz GPS 驯服钟 (GPSDO) - Part 1
  4. 字节跳动一面c++视频面试(第二个部门,效率工程部门)(一面通过)
  5. 我学编程全靠B站了,真香(第一期)
  6. Java web Servlet弹出提示框方法
  7. android 友盟统计动态设置渠道,Android 友盟多渠道打包
  8. 【iPhone】iPhone仅仅备份图片且保存实况图片(live photo)的方案
  9. 面试题 02.08. 环路检测-快慢指针+如何找到环的入口?(证明)Java
  10. e代驾——打造代驾服务标准化平台