iOS開發—執行緒之間資源共享(以賣火車票為例)—同步鎖的使用
阿新 • • 發佈:2019-01-05
程序中的一塊資源可能會被多個執行緒共享,也就是多個執行緒可能會訪問同一塊資源,這裡的資源包括物件、變數、檔案等。當多個執行緒同時訪問同一塊資源時,會造成資源搶奪,很容易引發資料錯亂和資料安全問題。
為了更好的理解執行緒安全的問題,引入一個賣票的案例,同時設定3個視窗賣票,模擬為每一個視窗開啟一個執行緒,共同訪問票數資源。新建一個Single View Application應用,名稱為02-ThreadSafeDemo,具體程式碼如下:
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,assign) int leftTicketCount;//剩餘票數
@end
@implementation ViewController
// 賣票
-(void)saleTickets
{
while(true)
{
//模擬延時,賣出一張票後,讓賣票的執行緒休眠1秒
[NSThread sleepForTimeInterval:1.0];
//判斷是否有票
@synchronized(self)
{
if(self.leftTicketCount>0)
{
//如果有賣一張
self.leftTicketCount--;
//提示餘額
NSLog(@"%@賣了一張票,剩餘%d張票",[NSThread currentThread].name,self.leftTicketCount);
}
else
{
//如果沒有,提示使用者
NSLog(@"沒有餘票");
return;
}
}
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//
self.leftTicketCount=50;
//
NSThread *t1=[[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
[email protected]"1號視窗";
[t1 start];
NSThread *t2=[[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
[email protected]"2號視窗";
[t2 start];
NSThread *t3=[[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
[email protected] "3號視窗";
[t3 start];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
該段程式碼總共建立了3個執行緒,每個執行緒都使用safeTickets方法來訪問同一個資源,並通過while迴圈不斷減少票數,然後列印剩餘票數。當程式執行成功後,單擊模擬器的螢幕,控制檯的執行結果如下:
這裡需要注意的是,3個執行緒執行併發操作,在同一時刻同時搶奪一個資源leftTicketCount,會造成剩餘票數統計的混亂,為了解決這個問題,我們在saleTickets方法裡面加入了同步鎖:
@synchronized(obj)
{
// 插入被修飾的程式碼塊
}
這個程式碼塊可簡稱為“同步程式碼塊”,obj就是鎖物件,,鎖物件就實現了對多執行緒的監控,保證同一時刻只有一個執行緒執行,當同步程式碼塊執行完成後,鎖物件就會釋放對同步監視器的鎖定。
需要注意的是,雖然Object-C允許使用任何物件作為同步鎖,但是考慮到同步鎖存在的意義是組織多個執行緒對同一個共享資源的併發訪問,因此同步鎖只要一個就可以了。並且同步鎖要監聽所有執行緒的整個執行狀態,考慮到同步鎖的生命週期,通常推薦使用當前的執行緒所在的控制器作為同步鎖。
由執行結果可以看出,通過給執行緒加同步鎖,成功的實現了執行緒的同步執行,也就是說,使多條執行緒按順序地執行任務,需要注意的是,同步鎖會消耗大量的CPU資源,一般的初學者很難把握好效能與功能的平衡,所以在開發中不推薦使用同步鎖。
注意:使用同步鎖的時候,要儘量讓“同步程式碼塊”包圍的程式碼範圍最小,而且要鎖定共享資源的全部讀寫部分的程式碼。