美文网首页
NSTherad详细介绍

NSTherad详细介绍

作者: 猿人 | 来源:发表于2019-12-04 17:58 被阅读0次

NSTherad

简介

NSThread 是封装最小、最轻量级的多线程编程接口,它使用灵活,但要手动管理线程的生命周期、线程同步和线程加锁等,开销较大

1、NSTherad创建

创建线程 手动启动线程

//创建线程
 NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
   //启动线程
 [thread start];

创建线程并自动启动线程

 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

隐式创建并启动线程


[self performSelectorInBackground:@selector(run) withObject:nil];

iOS10之后方法

  NSThread *thread = [[NSThread alloc]initWithBlock:^{
        //在此执行耗时操作
    }];
  [thread start];


///ios10之后可以使用 NSThreadWillExitNotification监听不到线程执行完毕
    [NSThread detachNewThreadWithBlock:^{
        //执行耗时操作
    }];


2、NSTherad方法属性介绍
//获取当前线程
@property (class, readonly, strong) NSThread *currentThread;

//判断是否是多线程
+ (BOOL)isMultiThreaded;
//返回线程对象的字典
@property (readonly, retain) NSMutableDictionary *threadDictionary;

//阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;

// 使当前线程睡眠指定的时间,单位为秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

// 退出当前线程
+ (void)exit;

//线程的调度优先级,取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
+ (double)threadPriority; 

 设置优先级程度在iOS8.0之后,建议使用qualityOfService属性
@property double threadPriority  
 
/*NSQualityOfService是个枚举,取值有如下优先级从高到低五种:

1.NSQualityOfServiceUserInteractive = 0x21 最高:主要用于与UI交互的操作,各种事件处理以及绘制图像等。
2.NSQualityOfServiceUserInitiated = 0x19 次高:执行一些明确需要立即返回结果的任务。例如,用户在邮件列表中选择邮件后加载电子邮件。
3.NSQualityOfServiceDefault = -1 默认:默认的优先级,介于次高级和普通级之间。
4.NSQualityOfServiceUtility = 0x11 普通:用于执行不许要立即返回结果、耗时的操作,下载或者一些媒体操作等。
5.NSQualityOfServiceBackground = 0x09 后台:后台执行一些用户不需要知道的操作,它将以最有效的方式运行。例如一些预处理的操作,备份或者同步数据等等。*/

@property NSQualityOfService qualityOfService  


//线程的名字 用于区分线程
@property (nullable, copy) NSString *name

//接收器的堆栈大小,以字节为单位
@property NSUInteger stackSize

//是否为主线程
@property (readonly) BOOL isMainThread

//当前线程对象是否正在执行任务
@property (readonly, getter=isExecuting) BOOL executing  

//当前线程对象是否已执行完任务
@property (readonly, getter=isFinished) BOOL finished  

//当前线程对象是否被取消
@property (readonly, getter=isCancelled) BOOL cancelled  

//取消当前线程
- (void)cancel  

// 开启线程
- (void)start  

//这个方法是线程的入口函数,当线程开启,默认会调用这个方法,并将线程入口函数selector和target传入,在该方法中对target调用selector。默认情况下,调用完毕,线程就被自动关闭了

- (void)main  


/////这个通知只会被NSThread触发一次,条件是当第一个进程在调用了start或者detachNewThreadSelector:toTarget:withObject:方法.这个通知的接收者的一些处理方法都是在主线程上进行的;这是因为这个通知是在系统生产新的子线程之前进行的,所以在监听这个通知的时候,调用监听者的通知方法都会在主线程进行.

//FOUNDATION_EXPORT NSNotificationName const NSWillBecomeMultiThreadedNotification;

/////这个通知目前没有实际意义,苹果也仅仅是保留这个扩展通知而已,并没有在NSThread的方法中,来触发这个消息,不过根据这个通知的字面意思来理解,是进程又回到单一线程的时候,会发送这个通知;但在多线程环境下, 这个没有什么实际的处理工作,可暂时忽略;

//FOUNDATION_EXPORT NSNotificationName const NSDidBecomeSingleThreadedNotification;

/////在线程被终止前会发送NSThreadWillExitNotification通知给通知中心。由于通知是同步发送的,因此可以确保在线程终止前,通知中心已经收到通知了。应该慎重调用这个方法,因为它无法保证资源的释放,造成内存泄露。

//FOUNDATION_EXPORT NSNotificationName const NSThreadWillExitNotification;

/* 线程间通信的方法
  * 多了一个modes参数,是用来设置runLoop模式
  */
- (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;
     
//可以从任意的两个线程之间作转换
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array  
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait  
//开启隐示线程
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg  

常用场景

耗时操作

/**
 * 下载图片,下载完之后回到主线程进行 UI 刷新
 */
- (void)downloadImage {
    NSLog(@"current thread -- %@", [NSThread currentThread]);

    // 1. 获取图片 imageUrl
    NSURL *imageUrl = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1575461632017&di=78230c4f59a22f2b08269356ecbb1197&imgtype=0&src=http%3A%2F%2Fimg.sccnn.com%2Fbimg%2F326%2F203.jpg"];

    // 2. 从 imageUrl 下载图片 耗时操作
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    // 通过二进制 data 创建 image
    UIImage *image = [UIImage imageWithData:imageData];

    // 3. 回到主线程进行图片赋值和界面刷新
    [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:image waitUntilDone:YES];
}

/**
 * 回到主线程进行图片赋值和界面刷新
 */
- (void)refreshOnMainThread:(UIImage *)image {
    NSLog(@"current thread -- %@", [NSThread currentThread]);

    // 赋值图片到imageview
    self.imageView.image = image;
}
  

NSThread 线程安全

如果多个线程同时访问读取一块地址空间 数据会错乱

举例子 一个食堂 2个窗口同时卖馒头 馒头总共100个 卖完为止

不考虑线程安全的代码:

-(void)initmesshall
{
    // 1. 设置馒头总共为 50个
    self. bunCount = 50;
    
    // 2. 设置食堂窗口1的线程
    self. messhallwindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(sellfood) object:nil];
    self.messhallwindow1.name = @"食堂售饭窗口1";
    
    // 3. 设置食堂窗口2的线程
    self.messhallwindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(sellfood) object:nil];
    self.messhallwindow2.name = @"食堂售饭窗口2";
    
    // 4. 开始卖馒头
    [self.messhallwindow1 start];
    [self.messhallwindow2 start];
 
}

/**
 * 售卖馒头(非线程安全)
 */
- (void)sellfood {
    while (1) {
 
        //如果还有馒头,继续卖
        if (self.bunCount > 0) {
            self.bunCount --;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余馒头数:%ld 窗口:%@", self.bunCount, [NSThread currentThread].name]);
            [NSThread sleepForTimeInterval:0.2];
        }
        //如果已卖完,关闭售卖窗口
        else {
            NSLog(@"所有馒头已售完");
            break;
        }
    
  }
}
```
打印 部分  发现数据错乱了 
```
2019-12-04 17:46:43.055837+0800 多线程test[34233:1942363] 剩余馒头数:18 窗口:食堂售饭窗口1
2019-12-04 17:46:43.055837+0800 多线程test[34233:1942364] 剩余馒头数:17 窗口:食堂售饭窗口2
2019-12-04 17:46:43.260489+0800 多线程test[34233:1942363] 剩余馒头数:16 窗口:食堂售饭窗口1
2019-12-04 17:46:43.260518+0800 多线程test[34233:1942364] 剩余馒头数:16 窗口:食堂售饭窗口2
2019-12-04 17:46:43.465406+0800 多线程test[34233:1942363] 剩余馒头数:15 窗口:食堂售饭窗口1
2019-12-04 17:46:43.465406+0800 多线程test[34233:1942364] 剩余馒头数:15 窗口:食堂售饭窗口2
2019-12-04 17:46:43.669683+0800 多线程test[34233:1942364] 剩余馒头数:13 窗口:食堂售饭窗口2
2019-12-04 17:46:43.669742+0800 多线程test[34233:1942363] 剩余馒头数:14 窗口:食堂售饭窗口1
2019-12-04 17:46:43.870421+0800 多线程test[34233:1942364] 剩余馒头数:12 窗口:食堂售饭窗口2
2019-12-04 17:46:43.870421+0800 多线程test[34233:1942363] 剩余馒头数:12 窗口:食堂售饭窗口1
2019-12-04 17:46:44.071775+0800 多线程test[34233:1942363] 剩余馒头数:10 窗口:食堂售饭窗口1
2019-12-04 17:46:44.071779+0800 多线程test[34233:1942364] 剩余馒头数:11 窗口:食堂售饭窗口2
2019-12-04 17:46:44.276647+0800 多线程test[34233:1942364] 剩余馒头数:9 窗口:食堂售饭窗口2
2019-12-04 17:46:44.276650+0800 多线程test[34233:1942363] 剩余馒头数:8 窗口:食堂售饭窗口1
2019-12-04 17:46:44.478485+0800 多线程test[34233:1942363] 剩余馒头数:7 窗口:食堂售饭窗口1
2019-12-04 17:46:44.478493+0800 多线程test[34233:1942364] 剩余馒头数:6 窗口:食堂售饭窗口2
2019-12-04 17:46:44.682709+0800 多线程test[34233:1942364] 剩余馒头数:5 窗口:食堂售饭窗口2
2019-12-04 17:46:44.682711+0800 多线程test[34233:1942363] 剩余馒头数:4 窗口:食堂售饭窗口1
2019-12-04 17:46:44.887120+0800 多线程test[34233:1942364] 剩余馒头数:3 窗口:食堂售饭窗口2
2019-12-04 17:46:44.887146+0800 多线程test[34233:1942363] 剩余馒头数:3 窗口:食堂售饭窗口1

```

线程安全解决方案:可以给线程加锁,在一个线程执行该操作的时候,不允许其他线程进行操作。

```
/**
 * 售卖馒头(线程安全)
 */
- (void)sellfood {
    while (1) {
        @synchronized (self) {
             
            //如果还有馒头,继续卖
                  if (self.bunCount > 0) {
                      self.bunCount --;
                      NSLog(@"%@", [NSString stringWithFormat:@"剩余馒头数:%ld 窗口:%@", self.bunCount, [NSThread currentThread].name]);
                      [NSThread sleepForTimeInterval:0.2];
                  }
                  //如果已卖完,关闭售卖窗口
                  else {
                      NSLog(@"所有馒头已售完");
                      break;
                  }
            
        }
      
    
  }
}
```
 打印发现 馒头数对上了 这就是考虑了线程安全

```
2019-12-04 17:53:57.698531+0800 多线程test[34292:1946779] 剩余馒头数:22 窗口:食堂售饭窗口2
2019-12-04 17:53:57.900181+0800 多线程test[34292:1946779] 剩余馒头数:21 窗口:食堂售饭窗口2
2019-12-04 17:53:58.100877+0800 多线程test[34292:1946779] 剩余馒头数:20 窗口:食堂售饭窗口2
2019-12-04 17:53:58.302771+0800 多线程test[34292:1946779] 剩余馒头数:19 窗口:食堂售饭窗口2
2019-12-04 17:53:58.506626+0800 多线程test[34292:1946779] 剩余馒头数:18 窗口:食堂售饭窗口2
2019-12-04 17:53:58.711036+0800 多线程test[34292:1946778] 剩余馒头数:17 窗口:食堂售饭窗口1
2019-12-04 17:53:58.915151+0800 多线程test[34292:1946778] 剩余馒头数:16 窗口:食堂售饭窗口1
2019-12-04 17:53:59.119483+0800 多线程test[34292:1946778] 剩余馒头数:15 窗口:食堂售饭窗口1
2019-12-04 17:53:59.322588+0800 多线程test[34292:1946778] 剩余馒头数:14 窗口:食堂售饭窗口1
2019-12-04 17:53:59.524112+0800 多线程test[34292:1946778] 剩余馒头数:13 窗口:食堂售饭窗口1
2019-12-04 17:53:59.728176+0800 多线程test[34292:1946778] 剩余馒头数:12 窗口:食堂售饭窗口1
2019-12-04 17:53:59.928589+0800 多线程test[34292:1946779] 剩余馒头数:11 窗口:食堂售饭窗口2
2019-12-04 17:54:00.133544+0800 多线程test[34292:1946778] 剩余馒头数:10 窗口:食堂售饭窗口1
2019-12-04 17:54:00.334732+0800 多线程test[34292:1946779] 剩余馒头数:9 窗口:食堂售饭窗口2
2019-12-04 17:54:00.539133+0800 多线程test[34292:1946779] 剩余馒头数:8 窗口:食堂售饭窗口2
2019-12-04 17:54:00.739621+0800 多线程test[34292:1946779] 剩余馒头数:7 窗口:食堂售饭窗口2
2019-12-04 17:54:00.941873+0800 多线程test[34292:1946778] 剩余馒头数:6 窗口:食堂售饭窗口1
2019-12-04 17:54:01.146433+0800 多线程test[34292:1946778] 剩余馒头数:5 窗口:食堂售饭窗口1
2019-12-04 17:54:01.351048+0800 多线程test[34292:1946778] 剩余馒头数:4 窗口:食堂售饭窗口1
2019-12-04 17:54:01.552734+0800 多线程test[34292:1946779] 剩余馒头数:3 窗口:食堂售饭窗口2
2019-12-04 17:54:01.788531+0800 多线程test[34292:1946779] 剩余馒头数:2 窗口:食堂售饭窗口2
2019-12-04 17:54:01.990576+0800 多线程test[34292:1946779] 剩余馒头数:1 窗口:食堂售饭窗口2
2019-12-04 17:54:02.195163+0800 多线程test[34292:1946779] 剩余馒头数:0 窗口:食堂售饭窗口2
```


  










相关文章

  • NSTherad详细介绍

    NSTherad 简介 NSThread 是封装最小、最轻量级的多线程编程接口,它使用灵活,但要手动管理线程的生命...

  • 开源协议介绍

    详细介绍 MPL (Mozilla Public License) 协议 详细介绍 MIT 协议 详细介绍 Apa...

  • iOS多线程之NSThread

    简介 苹果对 Pthreads 进行了面向对象的封装 NSTherad,使用起来比 pthread 更加面向对象,...

  • Linux Users and groups

    详细介绍

  • 奔驰详细介绍

  • zbus 详细介绍

    小巧而极速的MQ, RPC实现, 支持HTTP/TCP代理,开放易扩展,多语言支撑微服务,系统总线架构 zbus核...

  • Saltstack详细介绍

    自动化运维工具Saltstack详细介绍 标签:salt自动化运维salt-master 版权声明:原创作品,如需...

  • MagicalRecord详细介绍

    MagicalRecord,一个简化CoreData操作的工具库 简介 项目主页:https://github.c...

  • whoosh详细介绍

    Whoosh 是一个纯python实现的全文搜索组件。Whoosh不但功能完善,还非常的快。 Whoosh的作者是...

  • CocoaPods 详细介绍

    一、CocoaPods简介 iOS 和 OS X下的一个第三方库管理工具,类似的iOS工具还有Carthage(比...

网友评论

      本文标题:NSTherad详细介绍

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