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

13 篇文章 0 订阅
一、基本使用
1、三种创建子线程的方法
(1)NSThread直接创建,一个NSThread对象就代表一条线程
//实例化一个 NSThread对象
    NSThread *t1 = [[NSThreadalloc]initWithTarget:selfselector:@selector(longOperation:)object:@"NSThread"];
    // 启动线程
    [t1 start];

自定义一个耗时操作:
//耗时操作
- (void)longOperation:(id)obj {
    for (int i = 0; i < 10; ++i) {
        NSLog(@"%@ %d -- %@", [NSThreadcurrentThread], i, obj);
    }
}


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

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

2、主线程相关用法

+ (NSThread*)mainThread;// 获得主线程
- (BOOL)isMainThread;// 是否为主线程
+ (BOOL)isMainThread;// 是否为主线程

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


4、线程的调度优先级

+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;

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

- (void)setName:(NSString*)n;
- (NSString*)name;

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


启动线程:
- (void)start;
此时线程从就绪状态到运行状态

阻塞线程

+ (void)sleepUntilDate:(NSDate*)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

进入阻塞状态

强制停止线程

+ (void)exit;

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

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

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值