IOS开发多线程开发之线程安全篇

时间:2022-08-19 07:47:37 其他范文 收藏本文 下载本文

IOS开发多线程开发之线程安全篇(精选5篇)由网友“Serendipity”投稿提供,以下是小编帮大家整理后的IOS开发多线程开发之线程安全篇,欢迎大家收藏分享。

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)更简单的所方式,通常用在单例对象的创建上面

windows xp 组策略之安全篇Windows安全

ios学习之个人总结

C.net web开发面试题

ios个人总结学习

ios项目总结怎么写

iOS开发数据存储NSCoder

ios开发工程师简历自我介绍

安卓开发心得实例

安卓实习心得感悟

ios自我介绍范文

IOS开发多线程开发之线程安全篇
《IOS开发多线程开发之线程安全篇.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

【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

点击下载本文文档