美文网首页
iOS - 多线程NSThread的使用

iOS - 多线程NSThread的使用

作者: ShIwEn9 | 来源:发表于2019-08-03 11:03 被阅读0次

一、多线程的基本概念:

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。谢谢~~~

相关文章

网友评论

      本文标题:iOS - 多线程NSThread的使用

      本文链接:https://www.haomeiwen.com/subject/oloddctx.html