同步鎖:@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è)??
問題就是:多個(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é)果:
使用 @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ì)為它們提供顯式支持跪削,并且不建議使用它們谴仙。
參考博客: