iOS开发-多线程开发之线程安全篇
前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件和同一个方法等。因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安全等问题。因此要避免这些问题,我们需要使用“线程锁”来实现。
本文主要论述IOS创建锁的方法总结,如果大家对多线程编程技术这一块不熟悉,我建议你们先去看我的另一篇文章”iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)“
一、使用关键字
1)@synchronized(互斥锁)
优点:使用@synchronized关键字可以很方便地创建锁对象,而且不用显式的创建锁对象。
缺点:会隐式添加一个异常处理来保护代码,该异常处理会在异常抛出的时候自动释放互斥锁。而这种隐式的异常处理会带来系统的额外开销,为优化资源,你可以使用锁对象。
二、“Object-C”语言
1)NSLock(互斥锁)
2)NSRecursiveLock(递归锁)
条件锁,递归或循环方法时使用此方法实现锁,可避免死锁等问题。
3)NSConditionLock(条件锁)
使用此方法可以指定,只有满足条件的时候才可以解锁。
4)NSDistributedLock(分布式锁)
在IOS中不需要用到,也没有这个方法,因此本文不作介绍,这里写出来只是想让大家知道有这个锁存在。
如果想要学习NSDistributedLock的话,你可以创建MAC OS的项目自己演练,方法请自行Google,谢谢。
三、C语言
1)pthread_mutex_t(互斥锁)
2)GCD-信号量(“互斥锁”)
3)pthread_cond_t(条件锁)
线程安全 —— 锁
一、使用关键字:
1)@synchronized
// 实例类person Person *person = [[Person alloc] init];// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{@synchronized(person) {[person personA];[NSThread sleepForTimeInterval:3]; // 线程休眠3秒} });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{@synchronized(person) {[person personB];} });
关键字@synchronized的使用,锁定的对象为锁的唯一标识,只有标识相同时,才满足互斥。如果线程B锁对象person改为self或其它标识,那么线程B将不会被阻塞。你是否看到@synchronized(self) ,也是对的。它可以锁任何对象,描述为@synchronized(anObj)。
二、Object-C语言
1)使用NSLock实现锁
// 实例类person Person *person = [[Person alloc] init]; // 创建锁 NSLock *myLock = [[NSLock alloc] init];// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[myLock lock];[person personA];[NSThread sleepForTimeInterval:5];[myLock unlock]; });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[myLock lock];[person personB];[myLock unlock]; });
程序运行结果:线程B会等待线程A解锁后,才会去执行线程B。如果线程B把lock和unlock方法去掉之后,则线程B不会被阻塞,这个和synchronized的一样,需要使用同样的锁对象才会互斥。
NSLock类还提供tryLock方法,意思是尝试锁定,当锁定失败时,不会阻塞进程,而是会返回NO。你也可以使用lockBeforeDate:方法,意思是在指定时间之前尝试锁定,如果在指定时间前都不能锁定,也是会返回NO。
注意:锁定(lock)和解锁(unLock)必须配对使用
2)使用NSRecursiveLock类实现锁
// 实例类person Person *person = [[Person alloc] init]; // 创建锁对象 NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];// 创建递归方法 static void (^testCode)(int); testCode = ^(int value) {[theLock tryLock];if (value > 0){[person personA];[NSThread sleepForTimeInterval:1];testCode(value - 1);}[theLock unlock]; };//线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{testCode(5); });//线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[theLock lock];[person personB];[theLock unlock]; });
如果我们把NSRecursiveLock类换成NSLock类,那么程序就会死锁。因为在此例子中,递归方法会造成锁被多次锁定(Lock),所以自己也被阻塞了。而使用NSRecursiveLock类,则可以避免这个问题。
3)使用NSConditionLock(条件锁)类实现锁:
使用此方法可以创建一个指定开锁的条件,只有满足条件,才能开锁。
// 实例类person Person *person = [[Person alloc] init]; // 创建条件锁 NSConditionLock *conditionLock = [[NSConditionLock alloc] init];// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[conditionLock lock];[person personA];[NSThread sleepForTimeInterval:5];[conditionLock unlockWithCondition:10]; });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[conditionLock lockWhenCondition:10];[person personB];[conditionLock unlock]; });
线程A使用的是lock方法,因此会直接进行锁定,并且指定了只有满足10的情况下,才能成功解锁。
unlockWithCondition:方法,创建条件锁,参数传入“整型”。lockWhenCondition:方法,则为解锁,也是传入一个“整型”的参数。
三、C语言
1)使用pthread_mutex_t实现锁
注意:必须在头文件导入:#import <pthread.h>
// 实例类person Person *person = [[Person alloc] init];// 创建锁对象 __block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL);// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&mutex);[person personA];[NSThread sleepForTimeInterval:5];pthread_mutex_unlock(&mutex); });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&mutex);[person personB];pthread_mutex_unlock(&mutex); });
实现效果和上例的相一致
2)使用GCD实现“锁”(信号量)
GCD提供一种信号的机制,使用它我们可以创建“锁”(信号量和锁是有区别的,具体请自行百度)。
// 实例类person Person *person = [[Person alloc] init];// 创建并设置信量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[person personA];[NSThread sleepForTimeInterval:5];dispatch_semaphore_signal(semaphore); });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[person personB];dispatch_semaphore_signal(semaphore); });
效果也是和上例介绍的相一致。
我在这里解释一下代码。dispatch_semaphore_wait方法是把信号量加1,dispatch_semaphore_signal是把信号量减1。
我们把信号量当作是一个计数器,当计数器是一个非负整数时,所有通过它的线程都应该把这个整数减1。如果计数器大于0,那么则允许访问,并把计数器减1。如果为0,则访问被禁止,所有通过它的线程都处于等待的状态。
3)使用POSIX(条件锁)创建锁
// 实例类person Person *person = [[Person alloc] init];// 创建互斥锁 __block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); // 创建条件锁 __block pthread_cond_t cond; pthread_cond_init(&cond, NULL);// 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);[person personA];pthread_mutex_unlock(&mutex); });// 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{pthread_mutex_lock(&mutex);[person personB];[NSThread sleepForTimeInterval:5];pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex); });
效果:程序会首先调用线程B,在5秒后再调用线程A。因为在线程A中创建了等待条件锁,线程B有激活锁,只有当线程B执行完后会激活线程A。
pthread_cond_wait方法为等待条件锁。
pthread_cond_signal方法为激动一个相同条件的条件锁。
简单总结:
一般来说,如果项目不大,我们都会偷点懒,直接使用关键字@synchronized建立锁,懒人方法。其次可以使用苹果提供的OC方法,最后才会去使用C去建立锁。
本文参考文章:
iOS多线程开发(四)---线程同步
Objective-C中不同方式实现锁(一)
信号量与互斥锁
博文作者:GarveyCalvin
博文出处:http://www.cnblogs.com/GarveyCalvin/
本文版权归作者和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作!
转载于:https://www.cnblogs.com/GarveyCalvin/p/4212611.html
iOS开发-多线程开发之线程安全篇相关推荐
- 并发与多线程之线程安全篇
并发是指某个时间段内,多个任务交替执行的能力. CPU 把可执行时间均匀地分成若干份,每个进程执行一段时间后,记录当前的工作状态,释放当前的执行资源并进入等待状态,让其他进程抢占 CPU 资源.并行是 ...
- 转:使用NSOperationQueue简化多线程开发
原文:http://marshal.easymorse.com/archives/4519 使用NSOperationQueue简化多线程开发 多线程开发是一件需要特别精心的事情,即使是对有多年开发经 ...
- iOS开发多线程篇—多线程简介
iOS开发多线程篇-多线程简介 一.进程和线程 1.什么是进程 进程是指在系统中正在执行的一个应用程序 每一个进程之间是独立的.每一个进程均执行在其专用且受保护的内存空间内 比方同一时候打开QQ.Xc ...
- iOS开发多线程篇—自定义NSOperation
iOS开发多线程篇-自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...
- ios多线程开发的常用三种方式
ios多线程开发的常用三种方式 1.NSThread 2.NSOperationQueue 3.GCD NSThread: 创建方式主要有两种: [NSThread detachNewThreadSe ...
- iOS开发多线程篇—线程的状态
iOS开发多线程篇-线程的状态 一.简单介绍 线程的创建: self.thread=[[NSThread alloc]initWithTarget:self selector:@selector(te ...
- IOS多线程开发详解
概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...
- iOS多线程开发:几个容易被忽略的细节(马甲包)
一般情况下,iOS开发者只要会使用GCD.@synchronized.NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优 ...
- iOS多线程开发:几个容易被忽略的细节
一般情况下,iOS开发者只要会使用GCD.@synchronized.NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优 ...
最新文章
- Keras_insightface测试
- 掌握技术思想比解决问题本身更重要
- 什么是单模光纤收发器,应用范围有哪些?
- 【C/C++ 汇编语言 Verilog】越界截断——数据越界问题的多角度分析
- 华为估值知多少?倪光南:位居世界第一应该没问题
- 1900页Python系列PPT分享三:选择与循环结构语法及案例(96页)
- XCODE快捷键和功能汇总篇(不断更新)
- 构建小型Linux跟文件系统镜像(Ext2 或 Ext3)
- Machine Learning - 神经网络的表示和学习 (Week 4 - 5)
- python库阿里云镜像大全
- 使用xpath解析爬取链家
- MATLAB GUI 文献或书,MATLAB GUI程序设计epub
- Turtle图形绘制(绘制奥运五环)
- 【Face Recognition人脸识别】3. 单张图片人脸识别
- SEM谈谈如何摆脱Involute?
- hadoop错误org.apache.hadoop.yarn.exceptions.YarnException Unauthorized request to start container
- 简单的学生网页作业源码 基于HTML环保主题网页项目的设计与实现——环保垃圾分类(html css javascript)
- shell判断所输整数是否为质数
- 自考本科 04741 计算机网络原理 2022年10月真题以及答案(自己做的,仅供参考)
- web界面测试功能点
热门文章
- Java新鲜东西,带有标签的continue和break
- [YTU]_1032( 统计出其中英文字母、数字、空格和其他字符的个数)
- 多协程实例讲解(python 三)
- 快速幂(二进制,十进制)
- QT开发(十二)——QT事件处理机制
- Containerpilot 配置文件reload
- 内存动态分配之realloc(),malloc(),calloc()与new运算符
- POJ 3034 Whac-a-Mole(DP)
- SharePoint 2007 迁移所有数据库
- 一个简单的GridView分页