美文网首页
【多线程】NSThread

【多线程】NSThread

作者: 大基本功 | 来源:发表于2018-06-10 14:19 被阅读10次

    1️⃣创建和启动线程简单说明

    一个NSThread对象就代表一条线程

    创建、启动线程
     NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [thread start];
    // 线程一启动,就会在线程thread中执行self的run方法
    
    主线程相关用法
    + (NSThread *)mainThread; // 获得主线程
    - (BOOL)isMainThread; // 是否为主线程
    + (BOOL)isMainThread; // 是否为主线程
    
    其他用法
    //获得当前线程
    NSThread *current = [NSThread currentThread];
    //线程的调度优先级:调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
    + (double)threadPriority;
    + (BOOL)setThreadPriority:(double)p;
    //设置线程的名字
    - (void)setName:(NSString *)n;
    - (NSString *)name;
    

    创建线程后自动启动线程

    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
    //  隐式创建并启动线程  
    [self performSelectorInBackground:@selector(run) withObject:nil];
    //上述2种创建线程方式的优缺点
    //优点:简单快捷
    //缺点:无法对线程进行更详细的设置
    

    2️⃣线程安全

    一、多线程的安全隐患

    资源共享

    • 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源
    • 比如多个线程访问同一个对象、同一个变量、同一个文件
    • 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题

    示例一:

    示例二:

    问题代码:

    #import "YYViewController.h"
    11 
    12 @interface YYViewController ()
    13 //剩余票数
    14 
    15 @property(nonatomic,assign) int leftTicketsCount;
    16 @property(nonatomic,strong)NSThread *thread1;
    17 @property(nonatomic,strong)NSThread *thread2;
    18 @property(nonatomic,strong)NSThread *thread3;
    19 
    20 
    21 @end
    22 
    23 
    24 @implementation YYViewController
    25 
    26 
    27 - (void)viewDidLoad
    28 {
    29     [super viewDidLoad];
    30 
    31     //默认有20张票
    32 
    33     self.leftTicketsCount=10;
    34 
    35     //开启多个线程,模拟售票员售票
    36 
    37     self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    38 
    39     self.thread1.name=@"售票员A";
    40 
    41     self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    42 
    43     self.thread2.name=@"售票员B";
    44 
    45     self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    46     self.thread3.name=@"售票员C";
    47 }
    48 
    49  
    50 -(void)sellTickets
    51 {
    52     while (1) {
    53         //1.先检查票数
    54         int count=self.leftTicketsCount;
    55         if (count>0) {
    56             //暂停一段时间
    57             [NSThread sleepForTimeInterval:0.002];
    58 
    59             //2.票数-1
    60            self.leftTicketsCount= count-1;
    61  
    62             //获取当前线程
    63             NSThread *current=[NSThread currentThread];
    64             NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
    65         }else
    66         {
    67             //退出线程
    68             [NSThread exit];
    69         }
    70     }
    71 }
    72 
    73 
    74 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    75 { 
    76     //开启线程
    77 
    78    [self.thread1 start];
    79     [self.thread2 start];
    80     [self.thread3 start];
    81 
    82 }
    83 
    84 @end
    

    打印结果:

    image
    二、安全隐患分析
    三、如何解决
    • 互斥锁使用格式
    • @synchronized(锁对象) { // 需要锁定的代码 }
    • 注意:锁定1份代码只用1把锁,用多把锁是无效的
    43 -(void)sellTickets
    44 {
    45     while (1) {
    46         @synchronized(self){//只能加一把锁
    47         //1.先检查票数
    48 
    49         int count=self.leftTicketsCount;
    50         if (count>0) {
    51             //暂停一段时间
    52             [NSThread sleepForTimeInterval:0.002];
    53             //2.票数-1
    54 
    55            self.leftTicketsCount= count-1;
    56             //获取当前线程
    57             NSThread *current=[NSThread currentThread];
    58             NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
    59 
    60         }else
    61         {
    62             //退出线程
    63             [NSThread exit];
    64         }
    65         }
    66     }
    67 }
    

    执行效果图


    互斥锁的优缺点
    • 优点:能有效防止因多线程抢夺资源造成的数据安全问题
    • 缺点:需要消耗大量的CPU资源
    • 互斥锁的使用前提:多条线程抢夺同一块资源
    • 相关专业术语:线程同步,多条线程按顺序地执行任务
    • 互斥锁,就是使用了线程同步技术
    四:原子和非原子属性
    • OC在定义属性时有nonatomic和atomic两种选择
    • atomic:原子属性,为setter方法加锁(默认就是atomic)
    • nonatomic:非原子属性,不会为setter方法加锁
    • atomic加锁原理
    1 @property (assign, atomic) int age;
    2 
    3 - (void)setAge:(int)age
    4 { 
    5 
    6     @synchronized(self) { 
    7        _age = age;
    8     }
    9 }
    
    原子和非原子属性的选择
    • nonatomic和atomic对比
    • atomic:线程安全,需要消耗大量的资源
    • nonatomic:非线程安全,适合内存小的移动设备
    iOS开发的建议
    • 所有属性都声明为nonatomic
    • 尽量避免多线程抢夺同一块资源
    • 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

    3️⃣线程间通信

    线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信

    线程间通信的体现

    1个线程传递数据给另1个线程

    在1个线程中执行完特定任务后,转到另1个线程继续执行任务

    线程间通信常用方法

    • (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

    • (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

    线程间通信示例 – 图片下载

    12 @interface YYViewController ()
    13 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
    14 @end
    15 
    16 @implementation YYViewController
    17 
    18 - (void)viewDidLoad
    19 {
    20     [super viewDidLoad];
    21 }
    22 
    23  
    24 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    25 {
    26 // 在子线程中调用download方法下载图片
    27 
    28     [self performSelectorInBackground:@selector(download) withObject:nil];
    29 }
    30 
    31  
    32 -(void)download
    33 {
    34 
    35     //1.根据URL下载图片
    36     //从网络中下载图片
    37     NSURL *urlstr=[NSURL URLWithString:@"fdsf"];
    38 
    39     //把图片转换为二进制的数据
    40     NSData *data=[NSData dataWithContentsOfURL:urlstr];//这一行操作会比较耗时
    41 
    42     //把数据转换成图片
    43     UIImage *image=[UIImage imageWithData:data];
    44 
    45     //2.回到主线程中设置图片
    46     //第一种方式
    47 //    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
    48 
    49     //第二种方式
    50     //    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
    51 
    52     //第三种方式
    53    [self.iconView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
    54 }
    55 
    56 
    57 //设置显示图片
    58 //-(void)settingImage:(UIImage *)image
    59 //{
    60 //    self.iconView.image=image;
    61 //}
    62 
    63 @end
    

    参考

    相关文章

      网友评论

          本文标题:【多线程】NSThread

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