问题描述
1.在学习多线程安全的时候 学到了使用同步锁来避免多条线程并发执行时“同时”访问同一资源的情况。我想起了 之前学习atomic时,想起了该关键字是用来设置属性是否是线程安全的。于是我在程序中关闭了同步锁,并使用了上面的关键字来定义property 可是我在执行多线程操作后,发现这个设置并没有达到线程安全的效果。 请问是我的理解哪里出现了偏差了呢?
我的程序代码如下:
#import 'ThreadSafeVC.h'@interface ThreadSafeVC ()//售票员01@property (nonatomic, strong) NSThread *thread01;//售票员02@property (nonatomic, strong) NSThread *thread02;//售票员03@property (nonatomic, strong) NSThread *thread03;//火车票@property (atomic, assign) NSInteger totalTicket;@end@implementation ThreadSafeVC- (void)viewDidLoad{ [super viewDidLoad]; self.navigationItem.title = @'线程安全';_totalTicket = 100;//假设有100张火车票 [self createSubThreadsSaleTicket];}//创建子线程,售票- (void)createSubThreadsSaleTicket{ _thread01 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; _thread02 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; _thread03 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];[_thread01 setName:@'售票员01']; [_thread02 setName:@'售票员02']; [_thread03 setName:@'售票员03'];//开启线程 [_thread01 start]; [_thread02 start]; [_thread03 start]; }- (void)saleTicket{ while (true) {//添加 互斥锁//@synchronized (self)//这里有一个疑问 就是我将_totalTicket 设置成@property(atomic,xxxxx)的时候,关闭了这里的同步锁,发现依然线程不安全//{ [NSThread sleepForTimeInterval:0.03]; if (_totalTicket > 0) {_totalTicket--;NSLog(@'%----@---卖出了---%zd张---火车票', [NSThread currentThread].name, _totalTicket); } else {break; }//} } }@end
下面是部分输出结果: 请留意输出了 两个 98
2016-08-28 19:25:04.893 GYBase[2527:39769] 售票员01---卖出了---99张---火车票2016-08-28 19:25:04.893 GYBase[2527:39771] 售票员03---卖出了---98张---火车票2016-08-28 19:25:04.893 GYBase[2527:39770] 售票员02---卖出了---98张---火车票2016-08-28 19:25:04.925 GYBase[2527:39770] 售票员02---卖出了---96张---火车票2016-08-28 19:25:04.925 GYBase[2527:39771] 售票员03---卖出了---96张---火车票2016-08-28 19:25:04.925 GYBase[2527:39769] 售票员01---卖出了---95张---火车票2016-08-28 19:25:04.957 GYBase[2527:39770] 售票员02---卖出了---94张---火车票2016-08-28 19:25:04.958 GYBase[2527:39769] 售票员01---卖出了---93张---火车票2016-08-28 19:25:04.958 GYBase[2527:39771] 售票员03---卖出了---92张---火车票2016-08-28 19:25:04.987 GYBase[2527:39770] 售票员02---卖出了---91张---火车票2016-08-28 19:25:04.989 GYBase[2527:39769] 售票员01---卖出了---90张---火车票2016-08-28 19:25:04.989 GYBase[2527:39771] 售票员03---卖出了---89张---火车票2016-08-28 19:25:05.017 GYBase[2527:39770] 售票员02---卖出了---88张---火车票2016-08-28 19:25:05.019 GYBase[2527:39769] 售票员01---卖出了---87张---火车票2016-08-28 19:25:05.019 GYBase[2527:39771] 售票员03---卖出了---86张---火车票2016-08-28 19:25:05.052 GYBase[2527:39771] 售票员03---卖出了---84张---火车票2016-08-28 19:25:05.052 GYBase[2527:39770] 售票员02---卖出了---84张---火车票2016-08-28 19:25:05.052 GYBase[2527:39769] 售票员01---卖出了---83张---火车票2016-08-28 19:25:05.082 GYBase[2527:39771] 售票员03---卖出了---82张---火车票2016-08-28 19:25:05.082 GYBase[2527:39770] 售票员02---卖出了---82张---火车票
问题解答
回答1:_totalTicket--是对实例变量直接进行操作而不经过setter getter方法,而加了atomic特质的属性,会在对属性读写的时候进行加锁保证线程安全,如下
atomic的实现:- (void)setCurrentImage:(UIImage *)currentImage{ @synchronized(self) {if (_currentImage != currentImage) { [_currentImage release]; _currentImage = [currentImage retain];// do something} }}- (UIImage *)currentImage{ @synchronized(self) {return _currentImage; }}
所以你应该用.语法去访问。但atomic并不是绝对线程安全的相关资料
回答2:哦。多谢你的回答。感觉这个atomic有些差强人意了。我在好好看看。多谢!