IOS开发多线程开发之线程安全篇(精选5篇)由网友“Serendipity”投稿提供,以下是小编帮大家整理后的IOS开发多线程开发之线程安全篇,欢迎大家收藏分享。
篇1:IOS开发多线程开发之线程安全篇
前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件和同一个方法等,因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安全等问题。因此要避免这些问题,我们需要使用“线程锁”来实现。
本文主要论述IOS创建锁的方法(总结):
一、使用关键字
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
// 实例类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去建立锁。
篇2:IOS开发――多线程编程
1.“省电,流畅,优质应用,响应速度快,用户体验好……”也许是众多用户眼中的苹果系统,
2.在众手机商拼CPU主频,拼4核,8核的年代,苹果依然坚持双核,iphone用户体验仍然坚挺。
以上两点IOS是如何优化,在续航,流畅度和响应速度上完胜安卓,答案就是多线程&RunLoop...
RunLoop是IOS事件响应与任务处理最核心机制,它贯穿IOS整个系统运作,
RunLoop不像一般的线程循环等待任务,传统的线程循环等待任务会导致CPU时间被占用,虽然你设置了睡眠时间,但很多时候会出现空转,
而RunLoop是监控事件触发处理机制,说白了,在有事件的时候CPU全力生产,当没有事件产生的时候,线程就挂起等待事件。
可以说,RunLoop是IOS比android省电,流畅,用户体验好的主要原因。
篇3:iOS开发多线程基础知识 NSOperation
1.NSOperation的作用
·配合使用NSOperation和NSOperationQueue也能实现多线程编程
2.NSOperation和NSOperationQueue实现多线程的具体步骤
·先将需要执行的操作封装到一个NSOperation对象中
·然后将NSOperation对象添加到NSOperationQueue中
·系统会自动将NSOperation中封装的操作放到一条新线程中执行
---------NSOperation的子类----
3.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
4.使用NSOperation子类的方式有3种
·NSInvocationOperation
·NSBlockOperation
·自定义子类继承NSOperation,实现内部相应的方法
------NSInvocationOperation---
5.创建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
6.调用start方法开始执行操作
- (void)start;
一旦执行操作,就会调用target的sel方法
7.注意
·默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
·只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
-------NSBlockOperation--
8.创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
9.通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
-------NSOperationQueue----
10.NSOperationQueue的作用
·NSOperation可以调用start方法来执行任务,但默认是同步执行的
·如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
11.添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
-------最大并发数----
12.什么是并发数
·同时执行的任务数
·比如,同时开3个线程执行3个任务,并发数就是3
13.最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
-----队列的取消、暂停、恢复------
14.取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
15.暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
----操作优先级-----
16.设置NSOperation在queue中的优先级,可以改变操作的执行顺序
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
17.优先级的取值(优先级越高,越先执行)
·NSOperationQueuePriorityVeryLow = -8L,
·NSOperationQueuePriorityLow = -4L,
·NSOperationQueuePriorityNormal = 0,
·NSOperationQueuePriorityHigh = 4,
·NSOperationQueuePriorityVeryHigh = 8
---操作依赖---
18.NSOperation之间可以设置依赖来保证执行顺序
·比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
19.可以在不同queue的NSOperation之间创建依赖关系
20.注意:不能相互依赖
·比如A依赖B,B依赖A
----操作的执行顺序---
21.对于添加到queue中的operations,它们的执行顺序取决于2点
·首先依据NSOperation之间的依赖关系
·然后依据NSOperation的优先级
22.因此,总体的执行顺序是
·先满足依赖关系
·然后再从NSOperation中选择优先级最高的那个执行
---自定义NSOperation---
23.自定义NSOperation的步骤很简单
·重写- (void)main方法,在里面实现想执行的任务
24.重写- (void)main方法的注意点
·自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
·经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
--------分割线---
NSOperation小代码1,
只写一个文件参考下
// DYFViewController.m
// 624-03-NSOperation
//
// Created by dyf on 14-6-24.
// Copyright (c) ___FULLUSERNAME___. All rights reserved.
//
#import “DYFViewController.h”
@interface DYFViewController
@end
@implementation DYFViewController
- (void)viewDidLoad
{
[super viewDidLoad];
篇4:iOS开发多线程NSOperation和NSOperationQueue
NSThread能直观地控制线程对象,不过需要自己管理线程的生命周期,线程同步,用起来比较繁琐,而且比较容易出错,不过Apple给出了自己的解决方案NSOperation,它本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有NSInvocationOperation和NSBlockOperation两种方式,先补充一下NSThread的用法:
NSThread获取当前线程:
[NSThread currentThread]
performSelectorInBackground可以更新UI,不建议使用:
- (IBAction)update:(id)sender {
[self performSelectorInBackground:@selector(changeImage) withObject:nil];
}
图片背景更新:
-(void)changeImage{
NSLog(@“线程执行完之后更新图片”);
self.myImageView.image=[UIImage imageNamed:[NSString stringWithFormat:@“Thread2.jpg”]];
}
NSInvocationOperation和NSBlockOperation
这两种方式都很简单,其中NSInvocation的调用方式类似于NSThread,NSBlockOperation如果对Block有一点了解就可以,如果不明白的可以参考本人之前的Block文章 Object-C-代码块Block回顾,那么接下来的使用方式就很简单:
先来看下NSInvocationOperation的实例化方式:
//初始化
NSInvocationOperation *myInvocationOperation= [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationTaskMethod) object:nil];
//启动
[myInvocationOperation start];
调用方法:
-(void)operationTaskMethod{
NSLog(@“NSInvocationOperation初始化执行”);
}
NSBlockOperation的方式:
NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@“BlockOperation块执行”);
}];
[blockOperation start];
两种方式很方便,这个时候可以使用NSOperationQueue作为一个队列将线程包含在一起,首先定义一个NSOperationQuene:
@property (strong,nonatomic) NSOperationQueue *myOperationQuene;
这个时候需要调用:
NSInvocationOperation *myInvocationOperation= [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationTaskMethod) object:nil];
NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@“BlockOperation块执行”);
}];
self.myOperationQuene=[[NSOperationQueue alloc]init];
[self.myOperationQuene addOperation:myInvocationOperation];
[self.myOperationQuene addOperation:blockOperation];
上面最后的结果不确定,线程执行的顺序没法确定,如果想确定的按照顺序执行,需要添加一个依赖:
[blockOperation addDependency:myInvocationOperation];
添加依赖之后的,每次输出的结果一定是这样的:
-02-11 07:56:13.457 ThreadDemo[657:15033] NSInvocationOperation初始化执行
2015-02-11 07:56:13.457 ThreadDemo[657:15034] BlockOperation块执行
自定义NSOperation
每次一看到自定义,就感觉瞬间有了档次,然后参考一下前人的经验,不过网上的博客有的不好说,那感觉就像我像我只想吃一个鸡腿,确拿到了一个鸡腿堡,需要的不需要的都要自己一起吸收,
NSInvocationOperation和NSBlockOperation这两种方式不能满足业务需求,这个时候需要自定义的NSOperation,自定义的有两种分为非并发(NonConcurrent)和并发(Concurrent)两种形式,本文介绍非并发形式。
新建一个继承自NSOperation的MyCustomOperation,然后实现一下main方法:
//
// MyCustomOperation.h
// ThreadDemo
//
// Created by keso on 15/2/11.
// Copyright (c) keso. All rights reserved.
//
#import
@interface MyCustomOperation : NSOperation
@property (strong,nonatomic) NSString *customdata;
-(void)initData:(NSString *)data;
@end
NSOperation对象需要定期地调用isCancelled方法检测操作是否已经被取消,如果返回YES(表示已取消),则立即退出执行回收内存资源。所有NSOperation子类,一般用于代码比较容易终止的地方, 在循环的每次迭代过程中,如果每个迭代相对较长可能需要调用多次和没有执行工作之前调用。
//
// MyCustomOperation.m
// ThreadDemo
//
// Created by keso on 15/2/10.
// Copyright (c) 20 keso. All rights reserved.
//
#import “MyCustomOperation.h”
@implementation MyCustomOperation
- (void)initData:(NSString *)data{
if (self ==[super init])
_customdata= data;
}
- (void)main {
@try {
BOOL isDone = NO;
NSLog(@“循环之前的调用”);
while (![self isCancelled] && !isDone) {
// Do some work and set isDone to YES when finished
NSLog(@“已经运行成功了”);
isDone=YES;
}
}
@catch(...) {
NSLog(@“出现异常,请检查代码~”);
}
}
@end
如果需要调用定义的NSOPeration实例化之后Start即可:
MyCustomOperation *customOperation=[[MyCustomOperation alloc] init];
[customOperation start];
篇5:ios 开发中的多线程
iOS中使用多线程的原因:
1,iOS中只有主线程有直接修改Ui的权利
2,iPhone中主线程堆栈1M,新开辟的线程堆栈512K
3,多任务,多核,效率,用户体验共同决定
(一)GCD(Grand Central dispatch)block和dispatch,可以简化多核多线程编程,iOS4以后支持
1,block的定义类似于函数指针;block对象(块对象);
可以存在block数组;
但block存储在函数栈中,注意大括号中的生命周期;
2,block典型用法,图片下载应用中的块应用,嵌套异步block块的使用,如果前面ok,则去UI更新
dispatch_async(dispatch_queue_create(“com.enormego.EGOImageLoader”,NULL), ^{
UIImage* image = styler(anImage);
[[EGOCache currentCache] setImage:image forKey:keyForURL(aURL, style) withTimeoutInterval:604800];
dispatch_async(dispatch_get_main_queue(), ^{
completion(image, aURL, nil);
});
});
(二)NSOperation和NSOpertionQueue
1,一个继承自NSOperation的操作类,该类的实现中必须有 (void) main()方法
2,最简单的方法,将NSOperation的实例放入NSOpertionQueue中
3,可以在NSOpertionQueue中设置同时可以进行的操作数
(三)NSThread
1,detachNewThreadSelector此为简便方法,不用进行线程清理
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];
2,NSThread initialWithTarget, (void)start;方法,可以创建线程,但选择合适的时机启动线程
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(myThreadMainMethod:)
object:nil];
[myThread start];
(四)线程间同步
1,原子锁属性,automic,noautomic,变量可以保证多线程访问
2,NSCondition,可以提供带条件的同步锁,解锁时,需要输入相同的条件才能解锁
3,NSLock, lock,unlock比较简单的同步锁
4,@synchronized(anObject)更简单的所方式,通常用在单例对象的创建上面
★ 安卓开发心得实例
★ 安卓实习心得感悟
【IOS开发多线程开发之线程安全篇(精选5篇)】相关文章:
软件技术实习报告2023-08-04
浅析基于PC的开放式数控系统论文2022-04-29
4G软件工程师课程2023-01-30
计算机四级网络工程师试题及答案2022-05-15
java前端开发面试题2023-10-12
Java面试技巧攻略2022-11-06
Freemind软件介绍2024-02-05
HTML前端开发面试题及前端知识2023-03-28
安卓的英文是什么2023-11-13
Android字典造词功能2023-02-23