iOS基础知识梳理 - 多线程NSThread

2019-08-04  本文已影响0人  babyloveblues

一、线程的创建

#pragma mark - 线程的三种创建方法
// 创建线程方式1
- (void)createThread1{
    
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    [thread start];
    
}

// 创建线程方式2
- (void)createThread2{
    
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    [thread start];
    
}

// 创建线程方式3 隐式创建线程
- (void)createThread3{
    
    [self performSelectorInBackground:@selector(task) withObject:nil];
    
}

二、线程的状态

线程状态有就绪(runnable)、运行(running)、阻塞(blocked)、死亡(Dead)四种状态


线程状态示意图

三、控制线程状态

1. 启动线程

-(void)start; 进入就绪状态 ->运行状态。当线程任务执行完毕,自动进入死亡状态

2. 阻塞(暂停)线程

-(void)sleepUntilDate:(NSDate *)date;
-(void)sleepForTimeInterval:(NSTimeInterval)ti;
进入阻塞状态

3. 强制线程停止

值得注意的是,一旦线程死亡,就不能再次开启任务

// 创建线程方式1
- (void)createThread1{
    
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    [thread start];
    
}

/**
 线程上运行都的方法
 */
-(void)task{
    
    NSLog(@"task is running %@",[NSThread currentThread]);
    
    // 阻塞
    NSLog(@"线程睡了");
    [NSThread sleepForTimeInterval:1];
    NSLog(@"线程睡醒了");
    
    //死亡
    // 手动杀死线程
    [NSThread exit];
    NSLog(@"执行试一下");
    
}

四、线程的优先级

0.0 - 1.0 1.0是最高的默认是0.5。优先级高的线程不一定比优先级低的线程先执行,优先级高只是说明该线程有更多的可能被CPU执行。

/**
 线程的优先级
 */
-(void)priorityTest{
    
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    // name属性调试方便
    thread.name = @"thread————————>1";
    // 0.0 - 1.0 1.0是最高的默认是0.5
    // 优先级高的线程不一定比优先级低的线程先执行,优先级高只是说明该线程有更多的可能被CPU执行。
    thread.threadPriority = 0;
    [thread start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    thread2.name = @"thread2";
    [thread2 start];
    
}

五、安全隐患示例

  1. 银行存款1000元,同事异地取款各1000元这时候,现实的余额可能就会有偏差
  2. 火车票余票100张,两个终端各购买一张车票,余票数字显示可能会有问题

六、共享变量的问题

// nonatomic非原子属性:多线程环境下,多个线程可以同事读取和赋值
// atomic原子属性:多线程环境下,只有一个线程能对变量进行赋值,多个线程可以同事读取
// 相当于在set方法里面加了一个同步锁
// atomic我们称之为自旋锁
// 问题:自旋锁可不可以代替同步锁?
@property (atomic, strong) NSObject *obj1;
@property (nonatomic, strong) NSObject *obj2;
/**
 线程的优先级
 */
-(void)fakeSellTicketTest{
    
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(sellTicket) object:nil];
    // name属性调试方便
    thread.name = @"thread————————>1";
    // 0.0 - 1.0 1.0是最高的默认是0.5
    // 优先级高的线程不一定比优先级低的线程先执行,优先级高只是说明该线程有更多的可能被CPU执行。
    thread.threadPriority = 0;
    [thread start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sellTicket) object:nil];
    thread2.name = @"thread2";
    [thread2 start];
    
}

- (void)sellTicket{
    while (YES) {

        [NSThread sleepForTimeInterval:1];
        // 锁是一个任意对象,默认锁是开着的
        // 同步锁(互斥锁)
         @synchronized (self) {
            if (self.tickets > 0 ) {
                self.tickets = self.tickets - 1; 
                NSLog(@"%@ 余票%d", [NSThread currentThread], self.tickets);
                continue;
            }
         }
        NSLog(@"票卖完了");
        break;
    }
}

七、安全隐患的解决 - 互斥锁

  1. 互斥锁的使用
    @synchronized(锁对象){ //需要锁定的代码 }
    需要注意的是,锁定一份代码只用一把锁,用多把锁是无效的
  2. 互斥锁的优缺点
    优点:能有效的防止因多线程抢夺资源造成的数据安全问题
    缺点:需要消耗大量的CPU资源
  3. 互斥锁的使用前提:锁条线程抢夺同一块资源
  4. 专业术语
    线程同步的意思是:多条线程按顺序地执行任务
    互斥锁:就是使用了线程的同步技术

八、原子和非原子属性

  1. OC在定义属性时有nonatomic和atomic两种选择
  1. iOS开发建议

九、互斥锁和自旋锁

十、线程安全

十一、UI线程

十二、线程间通讯

  1. 什么叫做线程间通讯
  1. 线程间通讯的具体体现
  1. 线程间常用的通信方法
    -(void)performSelectorOnMainThread:(SEL)aSelector
    withObject:(id)arg waitUntilDone: (BOOL)wait;
    -(void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
  2. 具体示例 - 利用NSThread异步下载图片
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, weak) UIImageView *imgV;
@property (nonatomic, weak) UIScrollView *scrlView;
@end


@implementation ViewController

// 重写次方法,默认不会加载XIB和SB
- (void)loadView{
    
   [self createUI];
    
}

- (void)viewDidLoad {
   
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downLoadImg) object:nil];
    [thread start];
    
}

- (void)createUI{
    
    UIScrollView *scrlView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.scrlView = scrlView;
    self.view = scrlView;
    
    UIImageView *imgV = [[UIImageView alloc] init];
    self.imgV = imgV;
    [self.view addSubview:imgV];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    
}

-(void)downLoadImg{
    
    [NSThread sleepForTimeInterval:1];
    NSString *str = @"https://desk-fd.zol-img.com.cn/t_s1280x800c5/g5/M00/02/04/ChMkJ1bKx4qIGTZLAAmjEID8lj0AALH1ADgWvsACaMo983.jpg";
    NSURL *url = [NSURL URLWithString:str];
    // 获取图片资源
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *img = [UIImage imageWithData:data];
    
    // 线程间通信 子线程 -> 主线程
    //参数1: 方法
    //参数2: 方法参数
    //参数3: 等待执行完成
    [self performSelectorOnMainThread:@selector(updateUI:) withObject:img waitUntilDone: NO];
}

- (void)updateUI:(UIImage *)img{
    
    self.imgV.image = img;
    // 根据图片的大小显示图片
    [self.imgV sizeToFit];
    [self.scrlView setContentSize:img.size];
    
}
@end
上一篇下一篇

猜你喜欢

热点阅读