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

 

posted @ 2014-01-08 23:55  2020_xx  阅读(1005)  评论(0编辑  收藏  举报