上一篇介绍了常用的多线程技术,目前开发中比较常用的是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)等方法,以防止团队里的其他人通过另类的方法创建单例对象。