ios線程安全

多線程安全:

1塊資源可能會(huì)被多個(gè)線程共享,也就是多個(gè)線程可能會(huì)訪問(wèn)同一塊資源,比如多個(gè)線程訪問(wèn)同一個(gè)對(duì)象、同一個(gè)變量、同一個(gè)文件。當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題。

舉例1:一個(gè)可變數(shù)組?NSMutableArray *marray,數(shù)組里面有5個(gè)元素;當(dāng)兩個(gè)線程同時(shí)讀取到marray的count為1時(shí),都執(zhí)行remove操作數(shù)組會(huì)崩潰(注意不可能會(huì)同時(shí)訪問(wèn),只是兩次讀取操作訪問(wèn)的時(shí)間間隔非常逼近)

舉例2:比如對(duì)于@property(nonatomic,copy)NSString *str; 當(dāng)調(diào)用self.str = @"HELLO,GUY";如果是多線程,在一個(gè)線程執(zhí)行setter方法的時(shí)候,會(huì)涉及到字符串拷貝,另一個(gè)線程去讀取,很可能讀到一半的數(shù)據(jù),也就是garbage數(shù)據(jù)。

舉例3:

賣票
存錢

當(dāng)存錢1000和取錢1000這個(gè)過(guò)程幾乎同時(shí)發(fā)生,他們讀取余額都是1000,但是存錢過(guò)程執(zhí)行1000+1000這時(shí)余額變?yōu)?000,而隨后取錢過(guò)程執(zhí)行1000-500這時(shí)余額變成500;由于取錢過(guò)程稍晚于存錢,所以最終余額變?yōu)?00;這樣由于多線程問(wèn)題余額顯示異常

賣票問(wèn)題代碼:

?//剩余票數(shù)

?@property(atomic,assign) int leftTicketsCount;

?@property(nonatomic,strong)NSThread *thread1;

?@property(nonatomic,strong)NSThread *thread2;

?@property(nonatomic,strong)NSThread *thread3;


?????????//默認(rèn)有100張票

? ? ? ? ?self.leftTicketsCount=100;

? ? ? ? ?//開(kāi)啟多個(gè)線程,模擬售票員售票

? ? ? ? ?self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

?? ? ? ? self.thread1.name=@"售票員A";

? ? ? ? ? self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

? ? ? ? ? self.thread2.name=@"售票員B";

?? ? ? ? self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

?? ? ? ? self.thread3.name=@"售票員C";


-(void)sellTickets {

?? ? ? ? while(1) {

?? ? ? ? ? ? ? ? //1.先檢查票數(shù)

?? ? ? ? ? ? ? ? intcount=self.leftTicketsCount;

?? ? ? ? ? ? ? ? if(count>0) {

?? ? ? ? ? ? ? ? ? ? ? ? //暫停一段時(shí)間

?? ? ? ? ? ? ? ? ? ? ? ? [NSThreadsleepForTimeInterval:0.002];

?? ? ? ? ? ? ? ? ? ? ? ? //2.票數(shù)-1

? ? ? ? ? ? ? ? ? ? ? ? self.leftTicketsCount= count-1;

?? ? ? ? ? ? ? ? ? ? ? ? //獲取當(dāng)前線程

?? ? ? ? ? ? ? ? ? ? ? ? NSThread*current=[NSThreadcurrentThread];

?? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);

?? ? ? ? ? ? ? ? ? ? }else{

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //退出線程

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [NSThread exit];

?? ? ? ? ? ? ? ? ? ? ? ? ? ? }

?? ? ? ? ? ? }

}

會(huì)出現(xiàn)同時(shí)讀取數(shù)據(jù)的情況,A和B同時(shí)讀到票剩余50張,同時(shí)執(zhí)行票減一行為,此時(shí)實(shí)際剩余票數(shù)應(yīng)為:50-2

;而因?yàn)樽x到的都是50,最后結(jié)果變?yōu)?9

使用互斥鎖@synchronized(self){}保護(hù)self對(duì)象,在{}作用域內(nèi)防止self對(duì)象在同一時(shí)間內(nèi)被其它線程訪問(wèn)

sell tickets修改為:

? //默認(rèn)有20張票

?? ? ? ? self.leftTicketsCount=100;

?? ? ? ? //開(kāi)啟多個(gè)線程,模擬售票員售票

?? ? ? ? self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

?? ? ? ? self.thread1.name=@"售票員A";

? ? ? ? ? self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets2) object:nil];

? ? ? ? ? self.thread2.name=@"售票員B";

?? ? ? ? self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets3) object:nil];

?? ? ? ? self.thread3.name=@"售票員C";

-(void)sellTickets

?{

? ? ? @synchronized(self){

?? ? ? ? while(1) {

?? ? ? ? ? ? ? ? //1.先檢查票數(shù)

?? ? ? ? ? ? ? ? intcount=self.leftTicketsCount;

?? ? ? ? ? ? ? ? if(count>0) {

?? ? ? ? ? ? ? ? ? ? ? ? //暫停一段時(shí)間

?? ? ? ? ? ? ? ? ? ? ? ? [NSThreadsleepForTimeInterval:0.002];

?? ? ? ? ? ? ? ? ? ? ? ? //2.票數(shù)-1

? ? ? ? ? ? ? ? ? ? ? ? self.leftTicketsCount= count-1;

?? ? ? ? ? ? ? ? ? ? ? ? //獲取當(dāng)前線程

?? ? ? ? ? ? ? ? ? ? ? ? NSThread*current=[NSThreadcurrentThread];

?? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);

?? ? ? ? ? ? ? ? ? ? }else

?? ? ? ? ? ? ? ? ? ? ? ? {

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //退出線程

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [NSThreadexit];

?? ? ? ? ? ? ? ? ? ? ? ? ? ? }

?? ? ? ? ? ? }

? ? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 為什么CFRunLoopRef是線程安全的,而基于此的NSRunLoop卻不是線程安全的呢? 線程安全時(shí)多線程領(lǐng)域...
    小貓仔閱讀 1,333評(píng)論 2 4
  • UIKit是線程不安全的 UIKit是線程不安全的,并且這是蘋(píng)果有意的設(shè)計(jì),主要是為了提升性能。具體原因,下面這篇...
    松哥888閱讀 1,877評(píng)論 2 7
  • iOS線程安全的鎖與性能對(duì)比 一、鎖的基本使用方法 1.1、@synchronized 這是我們最熟悉的枷鎖方式,...
    Jacky_Yang閱讀 2,374評(píng)論 0 17
  • 一、基礎(chǔ)知識(shí):1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,565評(píng)論 0 4
  • 今天股票傻b不出,不過(guò)這算是馬后炮!因?yàn)樵谧罡叻宓臅r(shí)候,就是今天。 周三的一天,工作室,一直到深夜!晚飯都沒(méi)吃! ...
    DeathKnightR閱讀 176評(píng)論 0 0

友情鏈接更多精彩內(nèi)容