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)等方法,以防止团队里的其他人通过另类的方法创建单例对象。

 

你可能感兴趣的:(ios开发)