iOS开发 - 多线程实现方案之NSThread篇
NSThread API
//类方法:创建一个线程
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)); //类方法:直接创建并启动线程
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument; // 判断当前线程是否是多线程
+ (BOOL)isMultiThreaded; //返回线程对象的字典
@property (readonly, retain) NSMutableDictionary *threadDictionary; //阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date; // 使当前线程睡眠指定的时间,单位为秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti; // 退出当前线程
+ (void)exit; //线程的调度优先级,取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
// To be deprecated; use qualityOfService below 设置优先级程度在iOS8.0之后,建议使用qualityOfService属性
@property double threadPriority NS_AVAILABLE(10_6, 4_0); //NSQualityOfService是个枚举,取值有如下优先级从高到低五种:
//1.NSQualityOfServiceUserInteractive = 0x21 最高:主要用于与UI交互的操作,各种事件处理以及绘制图像等。
//2.NSQualityOfServiceUserInitiated = 0x19 次高:执行一些明确需要立即返回结果的任务。例如,用户在邮件列表中选择邮件后加载电子邮件。
//3.NSQualityOfServiceDefault = -1 默认:默认的优先级,介于次高级和普通级之间。
//4.NSQualityOfServiceUtility = 0x11 普通:用于执行不许要立即返回结果、耗时的操作,下载或者一些媒体操作等。
//5.NSQualityOfServiceBackground = 0x09 后台:后台执行一些用户不需要知道的操作,它将以最有效的方式运行。例如一些预处理的操作,备份或者同步数据等等。
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); //线程的名字 用于区分线程
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
//接收器的堆栈大小,以字节为单位
@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0); //是否为主线程
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0); //实例方法,可以获得线程对象
- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)); //当前线程对象是否正在执行任务
@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);
//当前线程对象是否已执行完任务
@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);
//当前线程对象是否被取消
@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);
//取消当前线程
- (void)cancel NS_AVAILABLE(10_5, 2_0);
// 开启线程
- (void)start NS_AVAILABLE(10_5, 2_0); // thread body method
//You should never invoke this method directly. You should always start your thread by invoking the start method.这个方法是线程的入口函数,当线程开启,默认会调用这个方法,并将线程入口函数selector和target传入,在该方法中对target调用selector。默认情况下,调用完毕,线程就被自动关闭了 - (void)main NS_AVAILABLE(10_5, 2_0); //这个通知只会被NSThread触发一次,条件是当第一个进程在调用了start或者detachNewThreadSelector:toTarget:withObject:方法.这个通知的接收者的一些处理方法都是在主线程上进行的;这是因为这个通知是在系统生产新的子线程之前进行的,所以在监听这个通知的时候,调用监听者的通知方法都会在主线程进行.
FOUNDATION_EXPORT NSNotificationName const NSWillBecomeMultiThreadedNotification; //这个通知目前没有实际意义,苹果也仅仅是保留这个扩展通知而已,并没有在NSThread的方法中,来触发这个消息,不过根据这个通知的字面意思来理解,是进程又回到单一线程的时候,会发送这个通知;但在多线程环境下, 这个没有什么实际的处理工作,可暂时忽略;
FOUNDATION_EXPORT NSNotificationName const NSDidBecomeSingleThreadedNotification; //在线程被终止前会发送NSThreadWillExitNotification通知给通知中心。由于通知是同步发送的,因此可以确保在线程终止前,通知中心已经收到通知了。应该慎重调用这个方法,因为它无法保证资源的释放,造成内存泄露。
FOUNDATION_EXPORT NSNotificationName const NSThreadWillExitNotification; //线程间通信的方法
//多了一个modes参数,是用来设置runLoop模式
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait; //可以从任意的两个线程之间作转换
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
//隐式创建并启动线程
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
实例运用及理解说明
1.创建线程的几种方式
//几种创建分线程的方式
//1.实例方法,需要手动开启线程,可以设置线程的更多属性
NSThread *threadOne = [[NSThread alloc]initWithTarget:self selector:@selector(startANewThreadOne:) object:nil];
[threadOne start]; //2.类方法,自动开启线程,不可设置线程更多属性
[NSThread detachNewThreadSelector:@selector(startANewThreadTwo:) toTarget:self withObject:nil]; //3.隐式创建方法
[self performSelectorInBackground:@selector(startANewThreadThree:) withObject:nil]; //4.ios10之后可以使用
NSThread *threadFour = [[NSThread alloc]initWithBlock:^{
//在此执行耗时操作
}];
[threadFour start]; //5.ios10之后可以使用 NSThreadWillExitNotification监听不到线程执行完毕
[NSThread detachNewThreadWithBlock:^{
//执行耗时操作
}];
2.相关属性及API简单使用
- (void)viewDidLoad {
[super viewDidLoad]; //监听线程退出的通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(threadWillExitNotice) name:NSThreadWillExitNotification object:nil]; //注意:线程的生命周期,当线程中的任务执行完成之后被释放掉
NSThread *threadOne = [[NSThread alloc]initWithTarget:self selector:@selector(startANewThreadOne:) object:@"分线程一"];
threadOne.name = @"threadOne";
threadOne.qualityOfService = NSQualityOfServiceUserInitiated;
NSMutableDictionary *dic = threadOne.threadDictionary;
[dic setObject:@"Bob" forKey:@"name"];
[dic setObject:@"" forKey:@"age"];
[threadOne start]; } -(void)startANewThreadOne:(id)param { if ([NSThread isMultiThreaded]) { for (int i = ; i < ; i++) {
NSLog(@"耗时操作 %d",i);
if (i == ) {
NSLog(@"睡会在干");
[NSThread sleepForTimeInterval:];
}
} NSThread *thread = [NSThread currentThread];
NSLog(@"-----> %@",thread.threadDictionary);
} }
3.线程的状态
init 后会创建一个线程对象,此时线程处于新建New的状态,调用start方法后,会将线程加入到可调度线程池中,此时进入就绪Runnable状态,当CPU调度到当前线程的时候,这时就会处于运行Running的状态,当CPU调度其他线程的时候,当前线程又回到就绪状态,当我们对当前线程调用了sleep或者等待同步锁的时候,此时又会进入线程阻塞Blocked状态, 这时线程对象会被移除可调度线程池,但还存在内存中,当时间到了的时候,重新进入到就绪状态,加入到可调度线程池中,当任务执行完毕或强制退出后,进入到死亡Dead状态,此时线程对象被释放
4.线程安全
多条线程抢夺同一块资源,可能会导致数据错乱和数据安全的问题。解决:互斥锁,加锁可以使线程同步(多条线程在同一条线上按顺序的执行任务)同时需要耗费性能
优点:有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
- (void)viewDidLoad {
[super viewDidLoad]; _ticketCount = ;//票的总量 NSThread *threadOne = [[NSThread alloc]initWithTarget:self selector:@selector(startSellTickets) object:nil];
threadOne.name = @"售票员1";
[threadOne start]; NSThread *threadTwo = [[NSThread alloc]initWithTarget:self selector:@selector(startSellTickets) object:nil];
threadTwo.name = @"售票员2";
[threadTwo start]; NSThread *threadThree = [[NSThread alloc]initWithTarget:self selector:@selector(startSellTickets) object:nil];
threadThree.name = @"售票员3";
[threadThree start]; }
- (void)startSellTickets { while () { //self : 锁对象,必须全局唯一,一般选择填self
@synchronized (self) { if (_ticketCount > ) { [NSThread sleepForTimeInterval:0.3];//模拟卖票的耗时操作
_ticketCount--;
NSLog(@"%@卖出去一张票,还剩%d张票",[NSThread currentThread].name,_ticketCount);
}else{
NSLog(@"end");
break;
}
} } }
卖票实例
5.原子和非原子属性
atomic:原子属性,线程安全,需要消耗大量的资源,为setter方法加锁(默认就是atomic)
nonatomic:非原子属性,非线程安全,适合内存小的移动设备
原文地址:去查看
//@property(nonatomic, retain) UITextField *userName;
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
} //@property(retain) UITextField *userName;
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName release];
userName = [userName_ retain];
}
}
6.线程间的通信
一个线程传递数据给另一个线程,在一个线程中执行完特定任务后,转到另一个线程继续执行任务,比如:在子线程中下载图片,在回到主线程展示图片
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
以上博文如有理解有误的地方,欢迎指正!
iOS开发 - 多线程实现方案之NSThread篇的更多相关文章
- iOS开发 - 多线程实现方案之Pthread篇
pthread基础 pthread是POSIX thread的简写,一套通用的多线程API,适用于Unix.Linux.Windows等系统,跨平台.可移植,使用难度大,C语言框架,线程生命周期由程序 ...
- iOS开发 - 多线程实现方案之GCD篇
GCD概念 GCD为Grand Central Dispatch的缩写,纯c语言编写,是Apple开发的一个多核编程的较新的解决方法.它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统.它是 ...
- iOS开发 - 多线程实现方案之NSOperation篇
NSOperation简介 1.实现多线程编程步骤: 配合使用NSOperation和NSOperationQueue实现多线程编程,我们不用考虑线程的生命周期.同步.加锁等问题,如下: 先将需要执行 ...
- iOS开发多线程--技术方案
pthread 实现多线程操作 代码实现: void * run(void *param) { for (NSInteger i = 0; i < 1000; i++) { ...
- iOS开发多线程篇—多线程简单介绍
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- iOS开发多线程篇—线程安全
iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
- iOS 开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇—创建线程
iOS开发多线程篇—创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] in ...
- iOS开发多线程篇—线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
随机推荐
- 谈谈EJB是怎样公布Web Service的
定义 我们常常会听到.xx项目中用到了Web Service.那么.什么是Web Service呢? 首先让我们来了解一下Web Service.Web Service技术.就是能使得执行在不同机器上 ...
- machine learning for hacker记录(4) 智能邮箱(排序学习&推荐系统)
本章是上一章邮件过滤技术的延伸,上一章的内容主要是过滤掉垃圾邮件,而这里要讲的是对那些正常的邮件是否可以加入个性化元素,由于每个用户关心的主题并非一样(有人喜欢技术类型的邮件或者购物促销方便的内容邮件 ...
- 一些js及css样式
人体时钟: 源码: <div> <embed wmode="transparent" src="https://files.cnblogs.com/fi ...
- C#开发遇到的常见问题及知识点
今天遇到的类型初始值设定项引发异常的原因是:类没有添加[Serializable]属性. this.DialogResult = System.Windows.Forms.DialogResult.O ...
- the art of seo(chapter seven)
Content Marketing ***Leveraging Major Social Media Platforms***LinkedIn, Facebook,Google+, Pinterest ...
- H3C-L2TP
l2tp enable #启用l2tp domain system authentication ppp local # 本地认证 access-limit disable state active ...
- 「USACO06FEB」「LuoguP2858」奶牛零食Treats for the Cows(区间dp
题目描述 FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving va ...
- 用C++发邮件
近段时间,实验室电脑的IP频繁地改变,搞得想用远程偷下懒都不行.这时想到的解决方法有:静态IP,动态域名,自己解决.静态IP虽然可以自己指定,但一关机后,与对方冲突就完了,作罢.免费的动态域名又要手机 ...
- 升级python之后yum不可用
#修改yum文件 vi /usr/bin/yum 将文件头部的 #!/usr/bin/python 改为默认的python文件,例如 #!/usr/bin/python2.7.3 整个过程完成了. 同 ...
- docker 学习(五) virtualBox虚拟机安装docker
这里计划用virtualBox虚拟机安装两个ubuntu servers, 然后用docker把spring boot项目部署上去,模拟一下分布式的微服务情况. 1:安装virtualbox,后安装U ...