最近两年多一直在忙着做项目,忽略了很多项目中常用的东西,这段时间得闲难得把一些东西总结一下,也是为了方便自己今后查看,这篇来谈谈三种多线程之一 NSThread
虽然不是最常用的但了解了解终归是好的
NSThread
作为三种多线程之一,他是最轻量级的,线程的声明的生命周期都需要自己手动管理,他的创建方法有三种第一种动态创建
/**
* NSThread三种直接间接创建方法
* 第一种静态动态创建方法
* selector最多只能接收一个参数
*/
NSThread *thread_1 = [[NSThread alloc] initWithTarget:self selector:@selector(thread1) object:nil];
thread_1.name = @"thread_1";
[thread_1 start];
这种方法需要手动开启线程,对应的selector最多只能接收一个参数
第二种静态创建
/**
* 第二种静态创建方法
*
*/
[NSThread detachNewThreadSelector:@selector(thread2) toTarget:self withObject:nil];
这种方法创建即启动
第三种隐式创建
/**
* 第三种隐式创建方法
*
*/
[self performSelectorInBackground:@selector(thread3) withObject:nil];
这种方式还有很多方法稍后一一说明
多线程说白了就是为了让我们的程序变的不是那么臃肿不卡顿而生,为了替主线程分担任务而存在,当我们不管什么操作都放在主线程中进行的时候你会发现你的程序恍如一个迟暮老人一样迟钝
NSThread
有很多方法 我这里把常用的一一列出
//打印出当前线程
NSLog(@"thread1 --- %@",[NSThread currentThread]);
//判断当前是否在多线程
NSLog(@"thread1 --- %d",[NSThread isMultiThreaded]);
//判断当前是否在主线程
NSLog(@"thread1 --- %d",[NSThread isMainThread]);
//让当前线程睡眠几秒
[NSThread sleepForTimeInterval:3.];
//让当前线程沉睡到指定时间
NSDate *date = [NSDate dateWithTimeInterval:2 sinceDate:[NSDate date]];
[NSThread sleepUntilDate:date];
刚才说了隐式创建的时候他对应的有多种方法,来看看有哪些
//回到主线程 执行UI操作
[self performSelectorOnMainThread:@selector(doSomeThing) withObject:nil waitUntilDone:YES];
这个方法很常用,因为我们一般在子线程中进行数据请求处理等等,处理完之后都要更新界面的,这个操作就需要回到主线程中去操作了
//在指定线程中进行某操作
[self performSelector:@selector(doSomeThing) onThread:thread_1 withObject:nil waitUntilDone:YES];
这个方法是当我们需要将某个操作添加到某个线程中进行的时候拿来用的。
NSThread
掌握这些最常用基本就够用了
下面来讨论一下线程锁的一些东西,我们用到多线程,那有关线程安全的问题就不能不考虑了,就比如一个很经典的例子,售票系统,有多个窗口同时售票这就是一个多线程,他们同时访问票务系统各自独立,这就导致了资源争夺的现象,可能A窗口在访问一块资源的时候,B窗口也在访问同一块资源,这就出现了这块资源到底给谁的问题,所以我们需要在A访问的时候把资源加锁,B只有等待A访问完了才能访问
关于线程锁我这里说最常用的三个
@synchronized(self) {}
NSLock
NSCondition
看到第一个是不是感觉很熟悉我们在定义属性的时候属性有个修饰符叫atomic
也叫原子性 加了这个属性就相当于把属性的setter方法里添加了@synchronized(self) {}
来保证安全,其实严格上讲他并不是安全的,这里随便说一种
当线程A,在setter方法里给属性设置值得时候,此时B线程在读属性的值,因为setter和getter方法是没有联系的,这时,A在执行到加锁,只是还没有设置值,然而B线程已经读取走了,本来是想读取A设置之后的值,却读取了设置之前的值,也就线程不安全了。
但是如果上面的AB线程都使用了同一把锁,对相应代码进行加锁,所以锁内的代码是线程安全的。所谓使用同一把锁就是@synchronized() {}
()中的对象是同一个
在这三种加锁方法中这一种是效率性能最低的
再来看第二个NSLock
//第二种
NSLock *lock = [[NSLock alloc] init];
[lock lock];
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[lock unlock];
这里加锁的部分是lock块里面的部分,这里可以防止不同的线程同时走这个方法的时候对n赋值出现冲突,在线程A赋值的时候,线程B也紧随其后,原本外界需要的是A赋的值可事与愿违拿到了B赋的值,所以加锁可以很有效的杜绝这种事情的发生A执行的时候加上锁B只能在外面等着A执行完
第三种NSCondition
//第三种
NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[condition unlock];
他也叫条件锁这个用起来稍微麻烦点,可以直接用上面的方法像NSLock一样用 也可以像下面一样 判断是否达到加锁条件之后再加锁
//第三种
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:1];
BOOL canLock = [conditionLock tryLockWhenCondition:1];
if (canLock) {
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[conditionLock unlock];
}
数字1就是他的判断条件,在外界可以定义几个宏,来作为判断条件,这里就不赘述了
这三种加锁方法如果不考虑性能的话第一种是不错的选择,如果考虑性能的话第二第三都可以,不过他们都不是性能最好的
还有一些别的加锁方法不过不常用,掌握这三个就已经够用了.
这些只是本人的一些见解有不对的地方欢迎指出,作者也是个奋斗在前线的coder,记录这些也是想加深自己对此的理解
下一篇来探究三种多线程中的下一种