一、多线程的基本概念:
1. 多线程的原理:
- 多线程是循环切换执行的
- 线程执行完毕之后会自动销毁
2. 多线程的优缺点:
- 优点:
- 提高程序的性能
- 充分利用cpu等的硬件资源
- 缺点:
- 当线程开的过多的时候,加重cpu的负荷,反而会降低性能。
- 多线程在使用的时候会增加程序的复杂度,除非在一些特殊情况下,比如:耗时操作,执行顺序固定等。
3. 线程和进程的关系:
- 进程是相对于系统而言的,一个应用程序相当于一个进程。
- 线程是相对于应用程序而言,一个进程可以有多个线程,并且至少有一个线程,主线程。
4. 多线程的状态:
如下图所示,线程的生命周期是:新建、就绪、运行、阻塞、死亡: 多线程的状态- 新建:通过实例化线程对象
- 就绪:线程向cpu发送start方法,线程对象就会被加入到线程池中,等待cpu的调度
- 运行:当cpu调度当前的cpu的时候,在线程执行完成之前,线程的状态会在“就绪”和“运行”状态中来回切换。
- 阻塞:通过sleep方法或者线程锁,将会使线程暂时被调离出线程池中。
sleepForTimeInterval(休眠指定时长),sleepUntilDate(休眠到指定日期),@synchronized(self):(互斥锁等各种锁) - 当任务执行完毕或者强制退出的时候,线程就回处于死亡状态。exit和cancel
- [NSThread exit]:一旦强行终止线程,后续的所有代码都不会被执行
- [thread cancel]取消:并不会直接取消线程,只是给线程对象添加 isCancelled 标记。
二、NSthread的基本使用:
1. 创建NSthread的几种方式:
- 方式一:通过对象方法 initWithTarget 来实现;
/**
创建一个子线程
Target: selector方法执行的对象
selector:执行的方法
object:携带的参数
*/
//不带参数
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(creatNewThread) object:nil] ;
// 就绪状态
[thread1 start];
// 带参数
NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(creatNewThreadTwo:) object:@"demo"] ;
// 就绪状态
[thread1 start];
-(void)creatNewThread{
NSLog(@"thread = %@", [NSThread currentThread]);
}
-(void)creatNewThreadTwo:(id) sender{
NSLog(@"sender = %@, thread = %@",sender, [NSThread currentThread]);
}
- 方式二:通过对象方法 detachNewThreadSelector 去创建
/**
创建一个子线程
Selector:执行的方法
toTarget:selector方法执行的对象
withObject:携带的参数
*/
[NSThread detachNewThreadSelector:@selector(creatNewThread) toTarget:self withObject:nil] ;
- 方式三 : 类自身去通过后台 performSelectorInBackground 创建一个新的线程
/*
- (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;
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
*/
[self performSelectorInBackground:@selector(creatNewThread) withObject:nil] ;
2. 线程的一些属性:
- 属性
@property NSQualityOfService qualityOfService; //线程优先级
@property (nullable, copy) NSString *name ; // 给线程设置名称
@property (class, readonly) BOOL isMainThread; // 是否是主线程
@property (readonly, getter=isExecuting) BOOL executing;//线程是否正在执行
@property (readonly, getter=isFinished) BOOL finished;//线程是否执行结束
@property (readonly, getter=isCancelled) BOOL cancelled;//线程是否可被取消
- 实例方法
-(void)start; //启动线程(init创建的线程,需start启动,不自行运行)
-(BOOL)isMainThread; //是否为主线程
-(void)setName:(NSString *)n; //设置线程名称
-(void)cancel ; //取消线程
-(void)main ; //线程的入口函数
-(void)isExecuting; //判断线程是否正在执行
-(void)isFinished; //判断线程是否已经结束
-(void)isCancelled; //判断线程是否撤销
- 类方法
+(void)currentThread; //获取当前线程
+(BOOL)isMultiThreaded; //当前代码运行所在线程是否是子线程
+(void)sleepUntilDate:(NSDate *)date; //当前代码所在线程睡到指定时间
+(void)sleepForTimeInterval:(NSTimeInterval)ti; //当前线程睡多长时间
+(void)exit; //退出当前线程
+(double)threadPriority; //设置当前线程优先级
/**给当前线程设定优先级,调度优先级的取值范围是0.0 ~ 1.0,
默认0.5,值越大,优先级越高。*/
+(BOOL)setThreadPriority:(double)p;
/**
线程的调用都会有函数的调用,函数的调用就会有栈返回地址的记录,
在这里返回的是函 数调用返回的虚拟地址,
说白了就是在该线程中函数调用的虚拟地址的数组
*/
+(NSArray *)callStackReturnAddresses;
+(NSArray *)callStackSymbols; //同上面的方法一样,只不过返回的是该线程调用函数的名字数字
三、线程锁的使用
通常情况下,当我们的程序出现资源抢占的时候,我们就会使用加锁操作。
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadAction) object:nil] ;
[thread1 start];
NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadAction) object:nil] ;
[thread2 start];
}
-(void)threadAction{
[NSThread sleepForTimeInterval:1.0f];
// 任意一个对象内部都有一把锁
// 每个对象里面的锁都是默认打开的
// 添加互斥锁
// 参数:锁 所在的对象
@synchronized (self) {
// synchronized: 线程同步: 多条线程按顺序去执行
while (YES) {
if (self.count > 0) {
self.count = self.count - 1 ;
NSLog(@"剩余:%ld",self.count);
}else{
NSLog(@"已结束");
break;
}
}
}
}
通常 锁 分为两种:
- 自旋锁
- 如果发现其他的线程正在执行锁定的代码,那么自旋锁就会一直去等待锁定的代码执行完毕。
- 同步锁
- 如果发现其他的线程正在执行锁定的代码,那么线程会进入休眠(就绪)状态,等到其他的代码的时间片打开了线程锁,那么该线程才会被唤醒去执行。
到这里NSthread的简单介绍就完成了, 如有不足之处请多多指教。
部分内容参考:
陌路卖酱油的iOS之多线程:线程的生命周期,NSThread、GCD、NSOperation的使用与总结
再次感谢
求职广告:本人实习生,现在急需一份工作,杭州南京合肥的都可以。对我感兴趣的可以私聊我 0.0。谢谢~~~
网友评论