您的位置:首页 > 移动开发 > IOS开发

ios线程第二发: NSThread(附录1)

2015-01-31 00:08 267 查看
NSThread:
1.创建、启动线程
1>手动启动的线程(经常使用)
// 线程一启动,就会在线程thread中执行self的run方法
NSThread *thread = [[[NSThread
alloc] initWithTarget:self
selector:@selector(run)
object:nil]
start]; 
 2>创建线程后自动启动线程
[NSThread
detachNewThreadSelector:@selector(run)
toTarget:self
withObject:nil];
3>隐式创建并启动线程
[self
performSelectorInBackground:@selector(run)
withObject:nil]
以上两种创建方法优缺点:创建快速简单,但是不能进行详细设置

(1)常用属性:
start:(将线程对象加入可调度线程池等待CPU调度)
线程的名字:name(可以自己设置)在商业级应用程序中,通常希望程序崩溃的时候,能够知道准确执行的线程!更容易排错
线程优先级:threadPriority默认0.5 取值范围是0.0—1.0  优先级高的调度频率比较高,不要进行修改优先级操作, 修改优先级有一个隐患->优先级翻转
线程的优先级:优先级高的任务只是表示 CPU 调度的频率高!
 误区:优先级高的任务会先执行完!

状态属性(只读):
             isExecuting 是否在执行
             isFinished 是否完成
             isCancelled 是否取消
线程大小:stackSize(默认线程都占用512kb,以前主线程1m, 子线程512k)
             可以自己设置,设置的时候是4k 得倍数
取消线程: cancle 可以在外部终止线程序执行,在执行方法中需要增加 isCancelled 判断,如果isCancelled == YES 直接返回

主线程相关用法
// 获得当前线程,开发中常用于调试,适用于所有线程技术number==1 表示主线程,其它为后台线程
+ (NSThread *)currentThread;
+ (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
+isMultiThreaded / / 是否为多线程

2.线程的状态
1>新建:实例化线程对象
2>就绪
   (1)向线程发送 start 消息,线程对象被加入”可调度线程池”等待 cpu 调度
   (2)detach 和 performSelectorInBackground 方法会直接实例化一个线程池对象并加入”可调度线程池”
3>运行
    (1)cpu 负责调度”可调度线程池”中线程的执行
    (2)线程执行完成之前,状态可能会在就绪和运行之间来回切换
    (3)就绪和运行之间的状态变化由 cpu 负责,程序员不能干预
4>阻塞
    (1)当满足某个预定条件时,可以使用休眠或者阻塞线程的执行: sleepFormTimeInterval,sleepUntilDate,@synchronized(self)
    (2)线程对象进入阻塞状态后,会被从”可调度线程池”中移除, cpu 不再调度
   
5>死亡
    (1)死亡方式: 正常死亡 —> 线程执行完毕
                      非正常死亡 —> 线程内死亡: [NSThread exit]
强制终止,后续代码不会执行
                                            线程外死亡:[NSThread acncell] 通知线程对象取消(在执行方法中需要增加 isCancelled 判断,如果 isCancell == YES ,直接返回)
     (2)死亡后线程对象的 isFinish 属性为 YES
     (3)如果发送cancell 消息,线程对象的 isCancell 属性为 YES
     (4)死亡后 stackSize == 0 ,内存空间被释放
 注意:一旦线程被强行终止了,后续所有代码都不会再继续执行!
        没有给线程机会释放执行过程中申请的资源
        exit 方法会直接终止线程,要调用之前,需要考虑释放对象
        ARC 中通常不用考虑,如果涉及到 c 语言混编,如果分配了 c 语言的对象,在 exit 之前,一定记住 release!           
                        
3.多线程的安全隐患解决 —— 互斥锁:
   1>安全隐患:(当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题)
   2>互斥锁/同步锁:
     (保证同一时间内,只有一条线程执行)(synchronized)
   
    3>互斥锁使用格式:
     @synchronized(锁对象) {
// 需要锁定的代码  }
   注意:
       互斥锁会降低性能,
       互斥锁锁定代码的范围,应该尽量的小
        使用互斥锁会影响并发的目的
       xcode 没有智能提示,因为互斥锁性能不好,苹果不建议使用
       synchronized(self) self 是一个能够加锁的 NSObject 对象,而且要保证所有线程都能共同访问到该对象
        一般情况而言, self 最方便使用加锁对象,如果程序只有一个地方涉及到加锁,绝大多数可以考虑使用 self
    
    4>原子属性(atomic)
        (1)能够实现”单写多读”的数据保护:
            同一时间只允许一个线程修改属性值,但是允许多个线程读取
            多线程读取数据的时候有可能出现脏数据, — 读取的数据可能会不正确
        (2)原子属性是默认属性,如果不考虑线程安全,要指定 
        (3)原子属性:nonatomic 和非原子属性: atomic
         原子属性 —> 默认属性: atomic
         原子属性是能够保证”线程安全”的属性,原子属性内部也有一把锁”自旋锁"
         自旋锁 和 synchronized
          A. 共同点:保证同一时间只有一个线程执行锁定范围内的代码
          B. 不同:  
          互斥锁: 当发现要执行的代码被其他线程锁定之后,线程会进入休眠状态,等待解锁之后,线程会被再次唤醒.
          自旋锁: 当发现要执行的代码被其他线程锁定之后,会以死循环的方式,监听是否解锁,一旦解锁,立即执行,执行性能高,适合于锁定非常短的代码
 
       5>线程安全:
          就是在多个线程同时对一个资源进行读写操作时,同样能够保证结果是正确的.
          要实现线程安全,必须要使用锁
          只要使用锁,就会降低性能
          
          UI 线程——主线程
          主线程又被称为 UI 线程,UIKIt 中几乎所有的控件都不是线程安全的,因此需要在主线程上更新 UI.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: