zoukankan      html  css  js  c++  java
  • ios开发之多线程资源争夺

    上一篇介绍了常用的多线程技术,目前开发中比较常用的是GCD,其它的熟悉即可。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用率来提高系统的整体性能,但是会出现多个线程对同一资源的抢夺,可能会引起线程的安全问题。 这时候可能需要创建一个单例对象来解决资源争夺问题,比较典型的是“卖票”问题

    1、单例对象的创建

      1> 定义一个全局的静态变量,记录第一次被实例化出来的对象,并在后续使用

      2> 重写allocWithZone方法,并利用dispatch_once_t实例化线程安全的对象

      3> 定义以shared或者default开头的类方法,供外界创建

     1 #import <Foundation/Foundation.h>
     2 
     3 @interface Tickets : NSObject
     4 
     5 // 要使用互斥锁,需要两个条件
     6 // 1. 将要强夺的资源设置为原子属性,只有设置了原子属性,才能够保证线程安全
     7 // 2. 在读写原子属性的代码处,使用互斥锁@synchronized
     8 @property (atomic, assign) NSInteger num; // 票数
     9 
    10 // 提供给外界的类方法,一般以shared或者default开头
    11 + (instancetype)sharedTickets;
    12 
    13 @end
     1 #import "Tickets.h"
     2 
     3 static Tickets *_instance;
     4 
     5 @implementation Tickets
     6 
     7 + (id)allocWithZone:(struct _NSZone *)zone
     8 {
     9     // dispatch_once_t是gcd提供的一种多线程实例化对象的方法
    10     // 使用此方法,可以保证在多线程情况下,始终仅能实例化出来一个对象
    11     static dispatch_once_t onceToken;
    12     dispatch_once(&onceToken, ^{
    13         _instance = [super allocWithZone:zone];
    14     });
    15     
    16     return _instance;
    17 }
    18 
    19 + (instancetype)sharedTickets
    20 {
    21     if (!_instance) {
    22         _instance = [[Tickets alloc] init];
    23     }
    24     
    25     return _instance;
    26 }
    27 
    28 @end

    2、 创建多个异步线程,并执行卖票方法

     1 - (void)viewDidLoad
     2 {
     3     [super viewDidLoad];
     4     
     5     [Tickets sharedTickets].num = 30;
     6     
     7     // 创建多个线程异步售票
     8     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     9     
    10     dispatch_async(queue, ^{
    11         [self sellTicketBy:@"p-1"];
    12     });
    13     
    14     dispatch_async(queue, ^{
    15         [self sellTicketBy:@"p-2"];
    16     });
    17     
    18 }

    3、 在访问原子属性时,加互斥锁

     1 - (void)sellTicketBy:(NSString *)name
     2 {
     3     while (YES) {
     4         
     5         // 在访问原子属性的地方加互斥锁
     6         @synchronized(self){
     7             if ([Tickets sharedTickets].num > 0) {
     8                 [Tickets sharedTickets].num--;
     9                 NSLog(@"剩余票数-%@-%d", name, [Tickets sharedTickets].num);
    10             }else{
    11                 NSLog(@"票卖完了");
    12                 break;
    13             }
    14         }
    15         
    16         // 让线程休眠,用于模拟售票员的效率不同
    17         if ([name isEqualToString:@"p-1"]) {
    18             [NSThread sleepForTimeInterval:1.0f];
    19         }else{
    20             [NSThread sleepForTimeInterval:0.5f];
    21         }
    22     }
    23 }

    至此一个简单的模拟售票,处理多线程资源争夺的demo就完成了。  

    但是还有几点需要注意的:

    1、互斥锁是非常消耗性能的,应该使加锁的内容越少越好

    2、单例对象里应该重写copy、retain(非ARC)等方法,以防止团队里的其他人通过另类的方法创建单例对象。

  • 相关阅读:
    404 页面不存在
    Elasticsearch 目录总结
    Excel 数据导入至Sqlserver 数据库中 ltrim() 、rtrim() 、replace() 函数 依次空格无效问题
    自动化测试工具-Selenium IDE 教程一
    搜索引擎背后的经典数据结构和算法
    如何收缩SQLServer 数据库日志文件大小?
    如何处理自我感动【转载】
    Microsoft.Jet.OLEDB.4.0 和 Microsoft.ACE.OLEDB.12.0 的区别
    windows 2012 IIS 部署 .net core HTTP Error 502.5
    Windows Server2012 KB2919355 补丁无法安装
  • 原文地址:https://www.cnblogs.com/liufeng24/p/3500560.html
Copyright © 2011-2022 走看看