ios多线程操作(二)—— NSThread的应用

一、基本使用
1、三种创建子线程的方法
(1)NSThread直接创建,一个NSThread对象就代表一条线程
[objc]  view plain  copy
  1. //实例化一个 NSThread对象  
  2.     NSThread *t1 = [[NSThreadalloc]initWithTarget:selfselector:@selector(longOperation:)object:@"NSThread"];  
  3.     // 启动线程  
  4.     [t1 start];  

自定义一个耗时操作:
[objc]  view plain  copy
  1. //耗时操作  
  2. - (void)longOperation:(id)obj {  
  3.     for (int i = 0; i < 10; ++i) {  
  4.         NSLog(@"%@ %d -- %@", [NSThreadcurrentThread], i, obj);  
  5.     }  
  6. }  


(2)、创建线程后自动启动线程
[objc]  view plain  copy
  1. // "隐式"的多线程方法!跟 detach 类方法类似,可以直接开启线程执行方法!  
  2.    [selfperformSelectorInBackground:@selector(longOperation:)withObject:@"perform"];  

该方法不需要调用start方法
(3)隐式创建并启动线程
[objc]  view plain  copy
  1. // performSelectorInBackground可以让任意一个 NSObject都具有在后台执行线程的能力!  
  2.     // 会让代码写起来非常灵活!  
  3. NSObject *obj = [[NSObjectalloc]init]  
  4. [obj performSelectorInBackground:@selector(loadData)withObject:nil];  

2、主线程相关用法

[objc]  view plain  copy
  1. + (NSThread*)mainThread;// 获得主线程  
  2. - (BOOL)isMainThread;// 是否为主线程  
  3. + (BOOL)isMainThread;// 是否为主线程  

3、获得当前线程 
[objc]  view plain  copy
  1. NSThread*current = [NSThreadcurrentThread];  
修改主线程的栈区大小:
[objc]  view plain  copy
  1. //修改主线程的栈区大小 => 1M  
  2. NSThreadcurrentThread].stackSize = 11024 * 1024;  


4、线程的调度优先级

[objc]  view plain  copy
  1. + (double)threadPriority;  
  2. + (BOOL)setThreadPriority:(double)p;  
  3. - (double)threadPriority;  
  4. - (BOOL)setThreadPriority:(double)p;  

   优先级的取值范围为0.0-1.0,线程默认优先级是0.5,最高是1.0。
      优先级高只能说明 CPU 在调度的时候,会优先调度,并不意味着优先级低的就不被调用或者后调用!
      在多线程开发的时候,不要去做不同线程之间执行的比较!线程内部的方法都是各自独立执行的,如果设置了优先级,那么就会有可能出现低优先级的线程阻塞高优先级的线程,也就是优先级反转!在ios开发中,多线程最主要的目的就是把耗时操作放在后台执行
5、为线程设置名字

[objc]  view plain  copy
  1. - (void)setName:(NSString*)n;  
  2. - (NSString*)name;  

二、线程状态
     每一个新建出来的线程被添加到可调度线程池中时就会处于就绪(runnable)状态,当CPU调度当前线程时,该线程会处于运行(running)状态,如果调用了sleep方法或者是等待同步锁时,该线程就会被移出可调度线程池,此时该线程处于阻塞(blocked)状态,当该线程sleep时间到时或得到同步锁又会被移入可调度线程池,此时该线程又处于就绪状态,当线程任务执行完毕或者异常强制退出时,该线程会处于死亡(dead)状态,如下图
ios多线程操作(二)—— NSThread的应用_第1张图片

启动线程:
[objc]  view plain  copy
  1. - (void)start;  
此时线程从就绪状态到运行状态

阻塞线程

[objc]  view plain  copy
  1. + (void)sleepUntilDate:(NSDate*)date;  
  2. + (void)sleepForTimeInterval:(NSTimeInterval)ti;  

进入阻塞状态

强制停止线程

[objc]  view plain  copy
  1. + (void)exit;  

此方法不会给任何机会去清理线程执行过程中分配的资源,也就是说一旦退出当前线程,后续所有代码不会执行(若后续代码中又释放内存的操作,那会相当的危险,会造成内存泄露),当使用C语言分配内存的时候要在该方法前适当的释放内存。

三、资源抢夺
     多线程会有安全隐患。1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件,当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。
     如何解决隐患问题——使用互斥锁
     假如有一个买票系统:
[objc]  view plain  copy
  1. - (void)saleTickets {  
  2.     while (YES) {  
  3.         //  模拟延时  
  4.         [NSThreadsleepForTimeInterval:1.0];  
  5.           @synchronized(self) {  
  6.             // 确认是否还有票(读取的动作)  
  7.             if (self.tickets > 0) {  
  8.                // 卖一张(写入动作)  
  9.                self.tickets--;  
  10.                  
  11.                //  输出剩余票数  
  12.                NSLog(@"剩余票数 %d %@"self.tickets, [NSThreadcurrentThread]);  
  13.             } else {  
  14.                 NSLog(@"没票了 %@", [NSThreadcurrentThread]);  
  15.                 break;  
  16.             }  
  17.         }  
  18.     }  
  19. }  
互斥锁的参数:
         1、self 本质上是任意一个 NSObject 都可以当成锁!
         2、 锁对象必须能够保证所有线程都能够访问(所以不可能是某个线程中的局部变量)
         3、 如果在程序中,只有一个位置需要加锁,可以使用self对象
使用互斥锁的效果就是卖票正确了,但效率却是下降了,在ios开发中尽量不要区抢夺资源,也不要区使用同步锁

四、原子属性,互斥锁与自旋锁
(1)原子属性
nonatomic : 非原子属性
atomic :原子属性,是默认属性
    * 是在多线程开发时,保证多个线程在"写入"的时候,能够保证只有一条线程执行写入操作!
    * 是一个单(线程)写多(线程)读的多线程技术
    * 原子属性,解决不了卖票问题,因为卖票的读写都需要锁定
    * 有可能会出现"脏数据",重新读取一下就可以!
    * 原子属性内部也有一把"锁"
    * 原子属性的锁的性能要比互斥锁高!
(2)自旋锁与互斥锁
每一个原子属性里面都会有一个锁,称之为自旋锁
共同点:
    都是保证同一时间,只有一条线程能够执行锁定范围的代码
区别:
    互斥锁:如果发现代码已经被(其他线程)锁定,当前线程会进入休眠状态,等锁解除之后,重新被唤醒
    自旋锁:如果发现代码已经被(其他线程)锁定,当前线程会以死循环的方式,一直判断锁是否解除,一旦接触立即执行!该锁,适合锁定非常短的代码,能够保证更高的执行性能!
互斥锁性能很差,在开发中很少用,只要是用到锁,性能都不高
(3) 线程安全
如果一个属性,在多个线程执行的情况下,仍然能够保证得到正确的结果,就叫做线程安全!要实现线程安全,就必须要使用到"锁"-> 性能不好!
 iso开发中UI 线程有个约定,所有UI更新,都需要在主线程上执行!
 原因:UIKit不是线程安全的!就是为了得到更高的性能!

你可能感兴趣的:(ios多线程操作(二)—— NSThread的应用)