zoukankan      html  css  js  c++  java
  • iOS开发多线程篇 03 —线程安全

    iOS开发多线程篇—线程安全

     

    一、多线程的安全隐患

    资源共享

    1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源

    比如多个线程访问同一个对象、同一个变量、同一个文件

    当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题

    示例一:

    示例二:

    问题代码:

    复制代码
     1 //
     2 //  YYViewController.m
     3 //  05-线程安全
     4 //
     5 //  Created by apple on 14-6-23.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 
    10 #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
    复制代码

     

    打印结果:

     

    二、安全隐患分析

     

     

    三、如何解决

     

    互斥锁使用格式

    @synchronized(锁对象) { // 需要锁定的代码  }

    注意:锁定1份代码只用1把锁,用多把锁是无效的

     

    代码示例:

    复制代码
     1 //
     2 //  YYViewController.m
     3 //  05-线程安全
     4 //
     5 //  Created by apple on 14-6-23.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYViewController.h"
    10 
    11 @interface YYViewController ()
    12 
    13 //剩余票数
    14 @property(nonatomic,assign) int leftTicketsCount;
    15 @property(nonatomic,strong)NSThread *thread1;
    16 @property(nonatomic,strong)NSThread *thread2;
    17 @property(nonatomic,strong)NSThread *thread3;
    18 @end
    19 
    20 @implementation YYViewController
    21 
    22 - (void)viewDidLoad
    23 {
    24     [super viewDidLoad];
    25     //默认有20张票
    26     self.leftTicketsCount=10;
    27     //开启多个线程,模拟售票员售票
    28 
    29     self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    30 
    31     self.thread1.name=@"售票员A";
    32 
    33     self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    34 
    35     self.thread2.name=@"售票员B";
    36 
    37     self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    38 
    39     self.thread3.name=@"售票员C";
    40 }
    41 
    42 
    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 }
    68 
    69 
    70 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    71 {
    72 
    73     //开启线程
    74    [self.thread1 start];
    75     [self.thread2 start];
    76     [self.thread3 start];
    77 }
    78 
    79 @end
    复制代码

    执行效果图

     

    互斥锁的优缺点

    优点:能有效防止因多线程抢夺资源造成的数据安全问题

    缺点:需要消耗大量的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

    尽量避免多线程抢夺同一块资源

    尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

  • 相关阅读:
    zoj 2316 Matrix Multiplication 解题报告
    BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告
    codeforces 463C. Gargari and Bishops 解题报告
    codeforces 463B Caisa and Pylons 解题报告
    codeforces 463A Caisa and Sugar 解题报告
    CSS3新的字体尺寸单位rem
    CSS中文字体对照表
    引用外部CSS的link和import方式的分析与比较
    CSS样式表引用方式
    10个CSS简写/优化技巧
  • 原文地址:https://www.cnblogs.com/LiLihongqiang/p/5598485.html
Copyright © 2011-2022 走看看