iOS 多线程(二)NSThread
来源:互联网 发布:中国8月进出口数据库 编辑:程序博客网 时间:2024/06/09 12:13
iOS 使用NSThread来代表线程,创建新线程也就是创建一个NSThread对象。
1 创建和启动线程
在iOS10之前提供了两种方法开启线程。
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;第一种方法是实例方法,返回一个NSThread对象,必须调用start方法来启动线程。
第二种方法是类方法,不会返回NSThread对象,直接创建并启动线程。
iOS10增加了两种创建启动线程的方法
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));这两个方法与上述类似,也是一个实例方法,一个类方法。只是执行方法体不一样了。
具体使用如下:
#import "ZPYViewController.h"@interface ZPYViewController ()@end@implementation ZPYViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self makeThread1beforeIOS10]; [self makeThread2beforeIOS10]; [self makeThread1FromIOS10]; [self makeThread2FromIOS10];}-(void)run{ for(int i=0;i<10;i++){ NSLog(@"%@,----i=%d",[NSThread currentThread],i); NSLog(@"isMainThread=%d",[NSThread isMainThread]); }}//iOS 10 之前NSThread两种方法创建线程。如下:-(void) makeThread1beforeIOS10{ //第一种创建方式 实例方法 最多可以传一个参数 NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread1 setName:@"fisrt blood"]; //启动线程 [thread1 start]; BOOL isMain = [NSThread isMainThread]; NSLog(@"isMain=%d,thread1=%d",isMain,[thread1 isMainThread]);}//第二种创建方式 类方法。 最多可以传一个参数-(void) makeThread2beforeIOS10{ //类方法,不会返回NSThread对象,直接启动线程 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];}//iOS 10又添加了两个方法创建线程。// 需要iOS 10 才可以运行下面两个方法。否则会出错。//第三种创建方式 实例方法-(void) makeThread1FromIOS10{ NSThread *thread3 = [[NSThread alloc] initWithBlock:^{ for(int i=0;i<10;i++){ NSLog(@"%@,第三种 i=%d",[NSThread currentThread],i); } }]; thread3.name = @"triple kill"; //调用start方法启动线程 [thread3 start];}//第四种创建方式 类方法-(void) makeThread2FromIOS10{ //类方法,不会返回NSThread对象,直接启动线程 [NSThread detachNewThreadWithBlock:^{ for(int i=0;i<10;i++){ NSLog(@"%@,第四种 i=%d",[NSThread currentThread],i); } }];}@end
2 常用方法
主线程相关:
+ (NSThread *)mainThread; // 获得主线程- (BOOL)isMainThread; // 是否为主线程+ (BOOL)isMainThread; // 是否为主线程其他方法:
获得当前线程
NSThread *current = [NSThreadcurrentThread];
线程的调度优先级
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
自己开发时,建议一般不要修改优先级
线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
3 线程的状态
NSThread *thread1 = [[NSThreadalloc]initWithTarget:selfselector:@selector(run)object:nil];
//启动线程
[thread1 start];
五种状态:新建、就绪、运行、阻塞、死亡。
新建:当程序建立一个线程后,该线程就处于新建状态,此时它和其他OC对象一样,仅仅有系统分配了内存,初始化了成员变量。
就绪:当线程对象调用start方法后,该线程处于就绪状态。处于该状态的线程并没有开始运行,至于何时运行,取决于系统的调度。
运行:当系统调度到该线程时,进入运行状态。调用到其他线程则该线程就又重新回到就绪状态。
阻塞:当线程调用了sleep方法或等待同步锁时进入阻塞状态。
死亡:当线程执行完毕,或异常/强制退出,则该线程进入死亡状态。
启动线程
- (void)start; //进入就绪状态-> 运行状态。当线程任务执行完毕,自动进入死亡状态
阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 进入阻塞状态
强制停止线程
+ (void)exit;
// 进入死亡状态
注意:一旦线程停止(死亡)了,就不能再次开启任务
4 停止线程
有时我们需要将子线程结束,这该怎么办呢?
线程结束方式又三种:
1 线程执行体方法执行完成,线程正常结束。
2 线程执行过程中发生了异常。
3 调用NSThread的exit方法类停止当前正在执行的线程。
由于exit方法为类方法,所以只能停止正在执行的线程。
我们可以在主线程或者其他线程中调用[thread cancel]。而子线程的执行体中可以判断是否cancel来停止线程。
//结束线程 if([[NSThread currentThread] isCancelled]){ [NSThread exit]; }
5 多线程安全
在多线程中,必然会涉及到线程安全点问题,比如资源共享(多个线程访问同一个对象、同一个变量、同一个文件),这时很容易发生数据错乱、数据安全问题。
如下经典问题,取钱
如上图:1500取出1600,还剩余700,这样显然是不合理的(虽然对于用户来说很乐意了)。
-(void)takeMoney:(NSNumber *)count{ [_account take:count.doubleValue];}- (IBAction)actionTest:(id)sender { _account = [[ZPYAccount alloc] initWithCardId:@"1234567" andBalance:1500]; NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(takeMoney:) object:[NSNumber numberWithInt:800]]; [thread1 setName:@"first thread"]; NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(takeMoney:) object:[NSNumber numberWithInt:800]]; [thread2 setName:@"second thread"]; [thread1 start]; [thread2 start];}两个线程去做取钱的操作。
ZPYAccount中的take方法:
-(void)take:(double)count{ double money = _balance; if(count <= money){ [NSThread sleepForTimeInterval:0.001]; _balance = money - count; NSLog(@"thread:%@,取钱成功,余额为%f",[[NSThread currentThread] name],_balance); }else{ NSLog(@"thread:%@,余额不足!",[[NSThread currentThread] name]); }}输出如下:
2016-10-11 11:40:09.052 NSThread使用[553:386755] thread:second thread,取钱成功,余额为700.0000002016-10-11 11:40:09.051 NSThread使用[553:386754] thread:first thread,取钱成功,余额为700.000000
1 @synchronized实现同步:
-(void)take:(double)count{ @synchronized (self) { //将需要同时执行的放入同步代码块中。查钱、取钱。 double money = _balance; if(count <= money){ [NSThread sleepForTimeInterval:0.001]; _balance = money - count; NSLog(@"thread:%@,取钱成功,余额为%f",[[NSThread currentThread] name],_balance); }else{ NSLog(@"thread:%@,余额不足!",[[NSThread currentThread] name]); } }}打印:
2016-10-11 18:45:52.135 NSThread使用[556:387839] thread:first thread,取钱成功,余额为700.0000002016-10-11 18:45:52.137 NSThread使用[556:387840] thread:second thread,余额不足!
这样就合理了,当余额不足时就不再让取钱,并且余额也没有问题。
2 NSLock 同步锁
使用NSLock也可以保证线程安全。
_lock = [[NSLockalloc]init];
-(void)takelock:(double)count{ [_lock lock]; double money = _balance; if(count <= money){ [NSThread sleepForTimeInterval:0.001]; _balance = money - count; NSLog(@"thread:%@,取钱成功,余额为%f",[[NSThread currentThread] name],_balance); }else{ NSLog(@"thread:%@,余额不足!",[[NSThread currentThread] name]); } [_lock unlock];}打印:
2016-10-11 18:52:09.216 NSThread使用[559:388860] thread:first thread,取钱成功,余额为700.0000002016-10-11 18:52:09.217 NSThread使用[559:388861] thread:second thread,余额不足!
- iOS 多线程(二)NSThread
- iOS多线程编程(二)------ NSThread
- ios多线程操作(二)—— NSThread的应用
- iOS多线程(二) 实现方案上(pthread,NSThread介绍)
- ios多线程操作(二)—— NSThread的应用
- iOS开发--多线程编程(二)NSThread买票
- iOS 多线程(一)NSThread
- ios多线程(NSThread)(swift)
- iOS多线程技术的深度探究二: NSThread多线程技术
- 多线程编程(二)NSThread的使用
- iOS多线程系列(1)NSThread
- iOS开发--多线程编程(一)NSThread
- iOS 多线程 NSThread
- IOS 多线程 NSThread
- iOS多线程 nsthread
- ios NSThread多线程
- iOS多线程开发 NSThread
- IOS 多线程 线程NSThread
- 《深入理解Java虚拟机》学习笔记
- 如何使用openssl生成RSA公钥和私钥对
- Codevs 1066 引水入城 2010年NOIP全国联赛提高组 BFS + 贪心
- 时间类型详解
- MFC--修改图标/开机动画/Combo控件
- iOS 多线程(二)NSThread
- Using Parser to Extract
- c#平台下singleton单件模式
- class文件简介
- Swift - 图片处理库ImageHelper详解(扩展UIImage,UIImageView)
- android 实现类似选项卡的UI
- 菜鸟窝-仿京东淘宝项目学习笔记(二)ToolBar的基本使用
- glide源码编译
- 试试手