美文网首页
NSThread-详解

NSThread-详解

作者: Q2我没有疯 | 来源:发表于2019-03-22 02:37 被阅读0次

当你想在线程中执行一个很长的任务,但又不希望它阻塞应用程序其余部分的执行时,子线程尤其有用,你可以将任务放在子线程中来执行,避免阻塞应用程序的主线程,让主线程处理用户界面和与事件相关的操作,子线程用于将大型任务划分为几个较小的任务,这能会使多核计算机上的性能提高。


NSThread使用

  • 获取主线程&当前线程
      // 获取主线程
      NSThread *mainThred = [NSThread mainThread];
      // 获取当前线程
      NSThread *currentThred = [NSThread currentThread];
    
  • 线程的创建
  1. 这种创建方式需要手动启动线程
- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一条线程(方式一)
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(runThread:) object:@"我是一条线程"];
    // 启动线程
    [thread start];
}
  1. 以下几种方式创建线程会自动启动线程,但是出了方式二以外的几种创建方式都无法对线程进行详细的设置。
// 方式二
   NSThread *thread = [[NSThread alloc] initWithBlock:^{
       
   }];
// 方式三
   [NSThread detachNewThreadWithBlock:^{
          NSLog(@"thread=%@-------",[NSThread currentThread]);
   }];
// 方式四
   [NSThread detachNewThreadSelector:@selector(runThread:) toTarget:self withObject:@"线程"];
// 方式五
   [self  performSelectorInBackground:@selector(runThread:) withObject:@"线程"];

  • 常用属性
// 优先级 0.0 ~ 1.0 默认 0.5 数值越大优先级越高
@property double threadPriority ; 

/** NSQualityOfService:
  NSQualityOfServiceUserInteractive:最高优先级,主要用于提供交互UI的操作,比如处理点击事件,绘制图像到屏幕上
  NSQualityOfServiceUserInitiated:次高优先级,主要用于执行需要立即返回的任务
  NSQualityOfServiceDefault:默认优先级,当没有设置优先级的时候,线程默认优先级
  NSQualityOfServiceUtility:普通优先级,主要用于不需要立即返回的任务
  NSQualityOfServiceBackground:后台优先级,用于完全不紧急的任务
*/
@property NSQualityOfService qualityOfService; 

// 线程名称(区别多条线程)
@property (nullable, copy) NSString *name;

// 线程正在执行
@property (readonly, getter=isExecuting) BOOL executing;

// 线程执行结束
@property (readonly, getter=isFinished) BOOL finished;

// 线程是否可以取消
@property (readonly, getter=isCancelled) BOOL cancelled;
  • 常用方法
-(void)start; // 启动线程

-(BOOL)isMainThread; // 是否为主线程

-(void)setName:(NSString *)n; // 设置线程名称

-(void)cancel ;// 取消线程

-(void)isExecuting; // 判断线程是否正在执行

-(void)isCancelled; // 判断线程是否撤销

-(void)isFinished; // 判断线程是否已经结束

+(void)currentThread; // 获取当前线程

+(BOOL)isMultiThreaded;  // 当前代码运行所在线程是否是子线程

+(void)sleepUntilDate:(NSDate *)date;  //当前代码所在线程睡到指定时间

+(void)sleepForTimeInterval:(NSTimeInterval)ti; //当前线程睡多长
时间

+(void)exit; // 退出当前线程
  • 线程的生命周期

当线程中的任务执行完成过后被释放

  • 线程的状态
    1. 就绪状态:当前线程准备就绪,CPU调度当前线程--->变为运行状态。
    2. 运行状态:当前线程运行中,当CPU调度其他线程--->变为就绪状态。
    3. 阻塞状态:当前线程调用sleep方法,等睡眠时间结束--->变为就绪状态。
    4. 死亡状态:线程任务执行完成,移出可调度线程池,被释放掉。

线程的安全

  • 如果多个线程(同时)访问同一资源时,很容易引发数据错乱和数据安全问题。


    线程安全.png

总共有100张电影票,当售票员01和02同时获取到余票为一百张时,01卖出了80张余票为20张,02卖出了21张余票为79张,实际上他们卖出了101张但是总票数只有100张,这样就多出一个人没法看电影,这就是引发数据错乱。


#import "ViewController.h"

@interface ViewController ()
@property (nonatomic,strong) NSThread *threadA;
@property (nonatomic,strong) NSThread *threadB;
@property (nonatomic,strong) NSThread *threadC;

@property (nonatomic,assign) NSInteger totalCount;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 总共设置100 票
    self.totalCount = 100;
    
    self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(runThread:) object:nil];
    self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(runThread:) object:nil];
    self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(runThread:) object:nil];
    
    self.threadA.name = @"售票员A";
    self.threadB.name = @"售票员B";
    self.threadC.name = @"售票员C";
    
    [self.threadA start];
    [self.threadB start];
    [self.threadC start];

}

-(void)runThread:(id)obj{
    while (1) {
        NSInteger count = self.totalCount;
        if (count>0) {
            for (int i = 0; i<1000; i++) { // 模拟售票时间
                self.totalCount = count - 1;
            }
            NSLog(@"%@卖了一张票还剩%zd",[NSThread currentThread].name,self.totalCount);
        }else{
            NSLog(@"售完了");
            break;
        }
    }
}
@end
输出结果.png
  • 互斥锁 「@synchronized () { }」
    • 锁是必须全局唯一的
    • 注意加锁的位置。
    • 注意加锁条件(多线程访问同一资源)
    • 加锁的结果会导致线程同步(多条线程在同一条线上执行,按顺序执行任务)

-(void)runThread:(id)obj{
 
    while (1) {
        // 锁:必须是全局唯一的
        @synchronized (self) {  // 互斥锁
            NSInteger count = self.totalCount;
            if (count>0) {
                for (int i = 0; i<1000; i++) { // 模拟售票时间
                    self.totalCount = count - 1;
                }
                NSLog(@"%@卖了一张票还剩%zd",[NSThread currentThread].name,self.totalCount);
            }else{
                NSLog(@"售完了");
                break;
            }
        }
    }
      
}
互斥锁结果.png

非原子属&性原子

  • nonatomic:非原子属性,不会为setter方法加锁,非线程安全,适合内存小的移动设备。
  • atomic:原子属性,为setter方法加锁(默认就是atomic),线程安全,需要耗费大量的资源。

线程间通信

  • 一个线程传递数据给另一个线程
  • 在一个线程中执行完成任务,转到另一个线程中继续执行任务(列如子线程下载图片,主线程显示图片)
  • 常用方法
// 从当前线程切换到主线程中
-(void)performSelectorOnMainThread:(SEL)aSelector
                        withObject:(id)arg
                     waitUntilDone:(BOOL)wait;
    
// 从当前线程切换到指定的线程
-(void)performSelector:(SEL)aSelector
              onThread:(NSThread *)thr
            withObject:(id)arg
         waitUntilDone:(BOOL)wait;

相关文章

  • NSThread-详解

    当你想在线程中执行一个很长的任务,但又不希望它阻塞应用程序其余部分的执行时,子线程尤其有用,你可以将任务放在子线程...

  • NSThread-多线程

    前言:关于线程和进程,其实不难理解,进程就相当于手机中的视频播放器,线程就相当于在视频播放器中观看视频,多线程相当...

  • OC-多线程编程学习之NSThread

    转载自:lysongzi.com/2016/02/23/iOS-多线程编程学习之NSThread-三/ 一个NST...

  • Mysql性能调优

    SQL执行原理详解 连接器详解 分析器详解 优化器详解 执行器详解 Innodb的Buffer Pool机制详解 ...

  • C/C++的30个冷知识

    数据格式详解 输入输出函数详解 字符串处理函数详解 内存函数详解 类详解 数据格式详解 2^8=256(同样是一个...

  • TSNE 详解

    TSNE 详解 TSNE 详解

  • SwiftSyntax 详解

    SwiftSyntax 详解SwiftSyntax 详解

  • 深入理解相机五(硬件抽象层HAL)

    一、Android 基础学习 Activity 使用详解 Service 使用详解 Broadcast 使用详解 ...

  • Lucene和ElasticSearch基本概念

    Lucene索引详解(IndexWriter详解、Document详解、索引更新)https://www.cnbl...

  • 自定义View的各个重要的类和属性

    1 、Path类详解 2、Paint详解 3、Canvas详解 4 、绘制雷达图

网友评论

      本文标题:NSThread-详解

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