同步鎖:@synchronized()

同步鎖:@synchronized()

官方解釋:The @synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code. The @synchronized directive does what any other mutex lock would do—it prevents different threads from acquiring the same lock at the same time. In this case, however, you do not have to create the mutex or lock object directly.

大概解釋一下:使用 @synchronized 可以快速創(chuàng)建互斥鎖玩讳,你可以不用創(chuàng)建任何互斥鎖或是鎖定某一對(duì)象就可以輕松阻止不同的線程在同一時(shí)間去獲取相同的鎖吻商。

1.@synchronized() 使用場(chǎng)景

在 APP 中,多線程競(jìng)爭(zhēng)同一資源的時(shí)候,會(huì)出現(xiàn)一些意想不到的結(jié)果雪情,比如數(shù)據(jù)錯(cuò)亂和安全的問題。

舉個(gè)??

241256038464378.png

問題就是:多個(gè)線程去修改票數(shù)碍侦,導(dǎo)致數(shù)據(jù)錯(cuò)亂的結(jié)果呐能。

那么如何去解決這個(gè)問題呢?

同步鎖解決資源共享就派上用場(chǎng)了尚揣,也就是給共享的資源加鎖涌矢,讓線程一個(gè)個(gè)地通過,以確保每次線程讀取的數(shù)據(jù)是正確的快骗。

#import "ViewController.h"

@interface ViewController ()

//剩余票數(shù)
@property(nonatomic,assign) int leftTicketsCount;
@property(nonatomic,strong)NSThread *thread1;
@property(nonatomic,strong)NSThread *thread2;
@property(nonatomic,strong)NSThread *thread3;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //默認(rèn)有20張票
    self.leftTicketsCount=10;
    //開啟多個(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)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //開啟線程
    [self.thread1 start];
    [self.thread2 start];
    [self.thread3 start];
}

-(void)sellTickets
{
    while (1) {
        
        @synchronized(self){//只能加一把鎖
            //1.先檢查票數(shù)
            int count=self.leftTicketsCount;
            if (count>0) {
                //暫停一段時(shí)間
                [NSThread sleepForTimeInterval:0.002];
                //2.票數(shù)-1
                
                self.leftTicketsCount= count-1;
                //獲取當(dāng)前線程
                NSThread *current=[NSThread currentThread];
                NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);
            }
            else{
                //退出線程
                NSLog(@"over!!!");
                NSLog(@"%@",[[NSThread currentThread] name]);
                [NSThread exit];//
                
            }
        }
        NSLog(@"name:%@ 解鎖成功方篮!",[[NSThread currentThread] name]);
    }
}
@end

打印結(jié)果:

QQ20161021-0.png

使用 @synchronized() 可以很輕松就解決線程同步存在的隱患名秀,但是在性能上卻不太友好,需要消耗大量的CPU資源藕溅, 主要是通過犧牲性能換來語(yǔ)法上的簡(jiǎn)潔與可讀匕得。為什么這樣說呢?我們來看看官方文檔的解釋:

As a precautionary measure, the @synchronized block implicitly adds an exception handler to the protected code. This handler automatically releases the mutex in the event that an exception is thrown. This means that in order to use the @synchronized directive, you must also enable Objective-C exception handling in your code. If you do not want the additional overhead caused by the implicit exception handler, you should consider using the lock classes.

大概解釋就是:在@synchronized 塊中巾表,隱藏地添加了一段異常處理的代碼汁掠,當(dāng)異常拋出時(shí),互斥鎖自動(dòng)解開集币。如果不想使用這一段異常處理代碼考阱,那就需要使用其他鎖來解決線程同步的問題吧。

如果想知道@synchronized 是如何實(shí)現(xiàn)的鞠苟,請(qǐng)移步于原理實(shí)現(xiàn)

延伸:下面簡(jiǎn)單減少一下 iOS 中常見一些鎖的概念

mutex

A mutually exclusive (or mutex) lock acts as a protective barrier around a resource. A mutex is a type of semaphore that grants access to only one thread at a time. If a mutex is in use and another thread tries to acquire it, that thread blocks until the mutex is released by its original holder. If multiple threads compete for the same mutex, only one at a time is allowed access to it.

互斥鎖在資源的周圍樹立了屏障乞榨。 互斥是一種類型的信號(hào)量秽之,它一次只允許訪問一個(gè)線程。 如果一個(gè)互斥體在使用姜凄,另一個(gè)線程試圖獲取它,該線程阻塞趾访,直到互斥體被其原始持有者釋放态秧。 如果多個(gè)線程競(jìng)爭(zhēng)同一互斥體,則一次只允許一個(gè)線程訪問它扼鞋。

Recursive lock

A recursive lock is a variant on the mutex lock. A recursive lock allows a single thread to acquire the lock multiple times before releasing it. Other threads remain blocked until the owner of the lock releases the lock the same number of times it acquired it. Recursive locks are used during recursive iterations primarily but may also be used in cases where multiple methods each need to acquire the lock separately.

遞歸鎖是互斥鎖上的一個(gè)變體申鱼。 遞歸鎖允許單個(gè)線程在釋放鎖之前多次獲取鎖。 其他線程保持阻塞云头,直到鎖的所有者釋放鎖的次數(shù)與它獲得的次數(shù)相同捐友。 遞歸鎖在遞歸迭代期間主要使用,但也可以在多個(gè)方法每個(gè)需要單獨(dú)獲取鎖的情況下使用溃槐。

Read-write lock

A read-write lock is also referred to as a shared-exclusive lock. This type of lock is typically used in larger-scale operations and can significantly improve performance if the protected data structure is read frequently and modified only occasionally. During normal operation, multiple readers can access the data structure simultaneously. When a thread wants to write to the structure, though, it blocks until all readers release the lock, at which point it acquires the lock and can update the structure. While a writing thread is waiting for the lock, new reader threads block until the writing thread is finished. The system supports read-write locks using POSIX threads only. For more information on how to use these locks, see the pthread man page.

讀寫鎖也稱為共享排它鎖匣砖。 這種類型的鎖通常用于大規(guī)模操作,并且如果受保護(hù)的數(shù)據(jù)結(jié)構(gòu)被頻繁地讀取并且僅僅偶爾被修改昏滴,則可以顯著地提高性能猴鲫。 在正常操作期間,多個(gè)讀取器可以同時(shí)訪問數(shù)據(jù)結(jié)構(gòu)谣殊。 當(dāng)線程想要寫入結(jié)構(gòu)時(shí)拂共,它阻塞,直到所有讀者釋放鎖姻几,此時(shí)它獲取鎖并且可以更新結(jié)構(gòu)宜狐。 當(dāng)寫線程正在等待鎖時(shí),新的讀線程阻塞直到寫線程完成蛇捌。 系統(tǒng)僅支持POSIX線程使用讀寫鎖抚恒。 有關(guān)如何使用這些鎖的更多信息,請(qǐng)參見pthread手冊(cè)頁(yè)络拌。

Distributed lock

A distributed lock provides mutually exclusive access at the process level. Unlike a true mutex, a distributed lock does not block a process or prevent it from running. It simply reports when the lock is busy and lets the process decide how to proceed.

分布式鎖在過程中提供了互斥訪問柑爸。 與真正的互斥體不同,分布式鎖不會(huì)阻止進(jìn)程或阻止進(jìn)程運(yùn)行盒音。 它只是報(bào)告鎖定是否忙表鳍,并讓進(jìn)程決定如何繼續(xù)。

Spin lock

A spin lock polls its lock condition repeatedly until that condition becomes true. Spin locks are most often used on multiprocessor systems where the expected wait time for a lock is small. In these situations, it is often more efficient to poll than to block the thread, which involves a context switch and the updating of thread data structures. The system does not provide any implementations of spin locks because of their polling nature, but you can easily implement them in specific situations. For information on implementing spin locks in the kernel, see Kernel Programming Guide.

自旋鎖重復(fù)輪詢其鎖定條件祥诽,直到該條件變?yōu)檎妗?自旋鎖最常用于多處理器系統(tǒng)上譬圣,其中鎖的預(yù)期等待時(shí)間很小。 在這些情況下雄坪,輪詢通常比阻塞線程更有效厘熟,這涉及上下文切換和線程數(shù)據(jù)結(jié)構(gòu)的更新。 由于其輪詢性質(zhì),系統(tǒng)不提供任何自旋鎖的實(shí)現(xiàn)绳姨,但是您可以在特定情況下輕松實(shí)現(xiàn)它們登澜。 有關(guān)在內(nèi)核中實(shí)現(xiàn)自旋鎖的信息,請(qǐng)參閱內(nèi)核編程指南飘庄。

Double-checked lock

A double-checked lock is an attempt to reduce the overhead of taking a lock by testing the locking criteria prior to taking the lock. Because double-checked locks are potentially unsafe, the system does not provide explicit support for them and their use is discouraged.

雙重檢查鎖是試圖通過在獲取鎖定之前測(cè)試鎖定標(biāo)準(zhǔn)來減少獲取鎖定的開銷脑蠕。 由于雙重檢查鎖可能不安全,因此系統(tǒng)不會(huì)為它們提供顯式支持跪削,并且不建議使用它們谴仙。

參考博客:

線程安全

官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碾盐,隨后出現(xiàn)的幾起案子晃跺,更是在濱河造成了極大的恐慌,老刑警劉巖毫玖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掀虎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡付枫,警方通過查閱死者的電腦和手機(jī)涩盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來励背,“玉大人春霍,你說我怎么就攤上這事∫睹迹” “怎么了址儒?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衅疙。 經(jīng)常有香客問我莲趣,道長(zhǎng),這世上最難降的妖魔是什么饱溢? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任喧伞,我火速辦了婚禮,結(jié)果婚禮上绩郎,老公的妹妹穿的比我還像新娘潘鲫。我一直安慰自己,他們只是感情好肋杖,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布溉仑。 她就那樣靜靜地躺著,像睡著了一般状植。 火紅的嫁衣襯著肌膚如雪浊竟。 梳的紋絲不亂的頭發(fā)上怨喘,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音振定,去河邊找鬼必怜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛后频,可吹牛的內(nèi)容都是我干的梳庆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼徘郭,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼靠益!你這毒婦竟也來了丧肴?” 一聲冷哼從身側(cè)響起残揉,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芋浮,沒想到半個(gè)月后抱环,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纸巷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年镇草,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘤旨。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梯啤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出存哲,到底是詐尸還是另有隱情因宇,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布祟偷,位于F島的核電站察滑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏修肠。R本人自食惡果不足惜贺辰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嵌施。 院中可真熱鬧饲化,春花似錦、人聲如沸吗伤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)牲芋。三九已至撩笆,卻和暖如春捺球,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夕冲。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工氮兵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歹鱼。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓泣栈,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親弥姻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子南片,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容