本文主要介绍iOS中NSThread使用实例的详细说明。有需要的朋友可以借鉴一下,希望能有所帮助。祝大家进步很大,早日升职加薪。
目录
text创建并启动线程线程的状态线程安全原子和非原子属性@同步线程间通信
正文
NSThread的对象代表一个线程,这是一个轻量级的线程操作。它的生命周期需要程序员来控制,任务完成后才释放。
创建和启动线程
创建代码有三种方式:
1.Allocnit创建一个线程,需要手动启动。
- (void)createNewThread1{
//1.创建一个线程
//第三个参数对象:前面调用方法需要传递的参数可以是nil。
NSThread * thread=[[NSThread alloc]initWithTarget:self selector:@ selector(run:)object:@ RC ];
//设置线程的名称
Thread.name=@ thread RC
//设置优先级范围为0.0-1.0,最高为1.0,默认优先级为0.5。
thread.threadPriority=1.0
/*
iOS8.0后新增线程优先级
@ property NSQualityOfService qualityOfService;
nsqualityofserviceusersinteractive-主线程
nsqualityofserviceuserpinitiated-高
NSQualityOfServiceUtility -低
NSQualityOfServiceBackground -背景
NSQualityOfServiceDefault -默认值
*/
//thread . qualityofservice=nsqualityofservice default;
//2.开始线程
[线程开始];
}
2.分离子线程并自动启动线程。
-(void)createNewThread2{
[nsthread detach thread selector:@ selector(run:)to target:self with object:@ detach child thread ];
}
3.打开一个后台线程并自动启动它。
-(void)createNewThread3{
[selperformselectorinbackground:@ selector(run:)with object:@ 启动后台线程];
}
-(void)run:(NSString *)param{
NSLog(@ - run - %@ - %@ ,[NSThread currentThread],param);
}
打印:
RCNSTHREADDemo[4644:223899]-RUN-NSThread:0x 60000 a 98480 { number=3,name=thread RC}-RC
RCNSTHREADDemo[4644:223901]-RUN-NSThread:0x 60000 a98a 00 { number=4,name=(null)}-分离子线程
rcnsthreaddemo[4644:223902]-Run-NSThread:0x 60000 a 99740 { number=5,name=(null)}-启动后台线程
主线程相关用法
(NSThread *)main thread;//获取主线程
-(BOOL)isMainThread;//是主线程吗?
(BOOL)isMainThread;//是主线程吗?
获取当前线程
NSThread * current=[NSThread current thread];
线程的状态
线程有五种状态:新、就绪、运行、阻塞和死亡。
启动线程:进入就绪状态-运行状态。线程任务完成后,会自动进入dead状态。
- (void)开始;
阻塞(暂停)线程:进入阻塞状态。
(void)sleepUntilDate:(ns date *)date;
(void)sleepForTimeInterval:(NSTimeInterval)ti;
强制线程停止:进入死状态。
(void)退出;
注意:一旦线程停止(死亡),就不能再启动任务了。
线程安全
因为同一个资源可能被多个线程共享,也就是多个线程可能访问同一个资源,比如多个线程访问同一个对象,同一个变量,同一个文件
当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题
。苹果官方安全风险分析图:
如上图,有两个线程A和B同时读取同一个地址得到17。a加1得18,然后写。这时B加1得到17,然后写。很明显,17做了两次1的运算,最后结果是18!
对于这种多个线程访问同一对象获得的结果是不可以预期的就出现了安全隐患。
苹果官方对此也给出了解决方案:如上图所示,ThreadA在访问资源之前,会添加一个锁并执行锁操作。再次读取资源,执行1次操作,结束后写入。同时,解锁资源并执行解锁操作。在此期间,任何其他线程都不能访问该资源,它必须等到解锁操作完成。此时,的其他线程处于等待状态。
注:
加锁是要消耗资源的
。看一下这个iOS线程锁及其关于锁的性能。
我们再延伸一下:
原子和非原子属性OC在定义属性时有两种选择:非原子和原子。据推测,我们大多数人使用非原子。
Atomic: Atomic属性,它实际上锁定了setter方法(默认为atomic)。如上所述,锁定后的线程是安全的,但会消耗大量资源。Nonatomic:非原子属性,不锁定setter方法,非线程安全,适合内存小的移动设备。
是:所有属性都应该声明为非原子的;尽量避免多线程抢夺同一块资源;尽可能把加锁和资源抢夺的业务逻辑交给服务器,减轻移动客户端的压力。
下面模拟线程安全风险,创建三个线程,从0开始进行1操作,直到超过10个停止代码:
//使用非原子来定义属性
@property (nonatomic,assign)NSInteger total count;
- (void)创建安全线程{
self . threada=[[NSThread alloc]initWithTarget:self selector:@ selector(get total)object:nil];
self . threadb=[[NSThread alloc]initWithTarget:self selector:@ selector(get total)object:nil];
self . threadc=[[NSThread alloc]initWithTarget:self selector:@ selector(get total)object:nil];
[self . threada start];
[self . threadb start];
[self . threadc start];
}
- (void)getTotal
while (1) {
NSInteger count=self . total count;
如果(计数10) {
//增加一个耗时的操作,效果更明显
for(n integer I=0;i88888i ) {
n integer a=1;
n integer b=1;
a=a b;
}
self . total count=count 1;
NSLog(@ - *-** - %ld ,self . total count);
}否则{
打破;
}
}
}
我们预期的打印应该是:从1到10依次打印,但是我们来看看真实的打印结果:
打印:
//截取部分打印
一个人
第二天
第二天
第三组
第四章
第三组
[1763:182365] - 5
第五章
第六章
第七章
一眼就能看出有问题。其实如果用GCD来模拟,会更明显。向并发队列中的for循环添加异步任务似乎会导致糟糕的内存访问和程序崩溃。
它还说,添加一个互斥锁将解决上述问题。在这里,它被用于:
@synchronized使用格式:@ synchronized {//code to locked },其中锁对象必须是唯一的,并且通常传递self或当前全局变量,如self.threadA
注意:一把锁只能锁一个码,多把锁无效。
互斥锁的优缺点
优点:可以有效防止多线程抢资源带来的数据安全问题。缺点:消耗大量CPU资源。
使用前提:多个线程抢同一个资源互斥会造成
线程同步
,即多个线程在同一行执行(按顺序执行任务)。上部代码:
- (void)getTotal
while (1) {
@同步(自己){
NSInteger count=self . total count;
如果(计数10) {
//增加一个耗时的操作,效果更明显
for(n integer I=0;i88888i ) {
n integer a=1;
n integer b=1;
a=a b;
}
self . total count=count 1;
NSLog(@ - %ld ,self . total count);
}否则{
打破;
}
}
}
}
线程间通信
线程间通信的常用方法
-(void)performSelectorOnMainThread:(SEL)as selector with object:(id)arg waitildone:(BOOL)wait;
-(void)perform selector:(SEL)aSelector on thread:(NSThread *)thr with object:(id)arg wauntil done:(BOOL)wait;
以下载图片为例:代码:
- (void)下载图像{
[NSThread detachNewThreadSelector:@ selector(download)to target:self with object:nil];
}
-(无效)下载{
NSRL * URL=[NSRL URL with string:@ http://00。迷你pic。东方日报。com/2017 07 227/2017 02 222714901 _ e 45455144 ba 23 b7cee 75 f 292229151 B1 _ 21。JPEG];
ns data * imagedata=[ns data datawithcontentsoffiurl:URL];
ui image * image=[ui image imagewithdata:图像数据];
//主线程显示图片等待时间(等待时间):是否等待,指的是后面代码的执行是否需要等待本次操作结束
//第一种
/[自我执行选择器:@ selector(show image:)on thread:[nsthread main thread]with object:image wauntilone:yes];
//第二种
【自我。imageview性能selectorominthread:@ selector(setimage:)with object:image wait idone:yes];
}
//更新你好操作
-(请参阅)显示图像:(uiimage *)图像[
self.imageView.image=映像:
nslog(@ ui % @ 、[当前线程]);
}
很简单,开启一个子线程来下载图片,再去主线程更新-你好。
以上就是去吧中恩斯特线程使用示例详解的详细内容,更多关于去吧中恩斯特线程使用的资料请关注我们其它相关文章!