iOS學習——鎖
阿新 • • 發佈:2017-11-12
方式 targe 賦值 void art getter pre select 在線
在多線程學習中,必然會涉及到不同線程對同一資源的調取,面對這種調用不加以控制,就會產生數據混亂的情況。最常見的情況莫過於買票,多個售票員售票肯定是同時操作,這樣就會開啟多條線程,但是這種售票方式會產生票數不對的情況。
- (void)demo1 { //售票員A NSThread *threadA = [[NSThread alloc] initWithTarget:self selector:@selector(sellTikets) object:nil]; threadA.name = @"threadA"; [threadA start];//售票員B NSThread *threadB = [[NSThread alloc] initWithTarget:self selector:@selector(sellTikets) object:nil]; threadB.name = @"threadB"; [threadB start]; } - (void)sellTikets{ while (YES) { if (self.tiketNum > 0) { self.tiketNum -- ; NSLog(@"還剩%d張票 %@",self.tiketNum,[NSThread currentThread]); }else { NSLog(@"票賣完了 %@",[NSThread currentThread]); break; } } }
這裏對於第九張票出售了兩次,這就是用多線程產生的數據不安全問題,因為在多線程的資源共享中,就得上一把鎖來保證不會出現這種問題
- (void)sellTikets{ while (YES) { @synchronized(self) {if (self.tiketNum > 0) { self.tiketNum -- ; NSLog(@"還剩%d張票 %@",self.tiketNum,[NSThread currentThread]); }else { NSLog(@"票賣完了 %@",[NSThread currentThread]); break; } } } }
@syn中需要傳一個全局變量參數,不一定是self,但是一定不能傳一個局部變量,因為這裏的參數作為一個鎖,要保證在線程執行的整個過程中都能鎖住線程,如果是一個局部變量,線程運行一次就被釋放掉了,根本毫無意義。
互斥鎖保證了線程在運行中,每次只有一個線程能訪問到被鎖住的代碼塊,其他需要訪問的線程則在鎖外面睡眠等待,當一個線程執行完畢,才有下一個線程的執行。那麽,我們就得提到OC中的另外一個概念,原子性 atomic。在變量的聲明時,我們大多是情況下都是用nonatomic,用以提高運行效率,那麽atomic的作用在哪裏呢?一般我們在寫文件的時候,會使用這樣的代碼:
NSData*data = [@"iosSynChronized" dataUsingEncoding:NSUTF8StringEncoding]; [data writeToFile:@"ios.text" atomically:YES];
為了保證文件寫入時候的安全,我們一般會選擇使用原子性。這樣,當文字在寫入的時候並不是直接創建一個本地文件寫數據,而是創建一個虛擬文件,當數據寫入完成,然後一次性形成要存儲的本地文件,就不會出現,寫入的時候你刪除文件,修改文件造成的數據沖突。類似於一個鎖一樣,鎖住你要操作的東西,只有完成才能結束。同樣,給變量聲明atomic也就等於給變量賦值創建了一把鎖,只有一個線程完成對該變量的操作,下一個線程才能進行:
@property (atomic, strong) NSObject *lock; @end @implementation ViewController @synthesize lock = _lock;//重新getter和setter方法後,xcode就不會自動幫寫成員變量 -(void)setLock:(NSObject *)lock { @synchronized (self) { _lock = lock; } } - (NSObject *)lock { return _lock;
鎖能夠保證數據安全,但同樣也因此帶來了極大的不便,那就是效率問題,它將所有訪問操作都變成了單一操作,會浪費大量時間,這也是蘋果的UIKIT同樣采用線程不安全方式的原因,考慮到了效率問題。
iOS學習——鎖