1 前言
近日工作不是太忙,剛好有時間了解一些其他東西挑随,本來打算今天上午去體檢状您,但是看看天氣還是明天再去吧,也有很大一個原因:就是周六沒有預(yù)約上兜挨!閑話少說膏孟,這里簡單對鎖來個簡單介紹分享。
2 目錄
第一部分:什么是鎖
第二部分:鎖的分類
第三部分:鎖的作用
第四部分:iOS中鎖的實現(xiàn)
第一部分:什么是鎖
從小就知道鎖拌汇,就是家里門上的那個鎖柒桑,用來防止盜竊的鎖。它還有鑰匙担猛,用于開鎖幕垦。不過這里的鎖,并不是小時候認知的鎖傅联,而是站在程序員的角度的鎖先改。這里我就按照我的理解來介紹一下鎖。
在計算機科學中蒸走,鎖是一種同步機制仇奶,用于在存在多線程的環(huán)境中實施對資源的訪問限制。你可以理解成它用于排除并發(fā)的一種策略比驻「盟荩看例子
1
2
3
4
5if(lock?==?0)?{
lock?=?myPID;
}
上面這段代碼并不能保證這個任務(wù)有個鎖,因此它可以在同一時間被多個任務(wù)執(zhí)行别惦。這個時候就有可能多個任務(wù)都檢測到lock是空閑的狈茉,因此兩個或者多個任務(wù)都將嘗試設(shè)置lock,而不知道其他的任務(wù)也在嘗試設(shè)置lock掸掸。這個時候就會出問題了氯庆。 再看看這段代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14classAcccount?{
longval?=?0;//這里不可在其他方法修改蹭秋,只能通過add/minus修改
object?thisLock?=newobject();
publicvoidadd(constlongx)?{
lock(thisLock)?{
val?+=x;
}
}
publicvoidminus(constlongx)?{
lock(thisLock)?{
val?-=x;
}
}
}
這樣就能防止多個任務(wù)去修改val了,(這里注意堤撵,如果val是public的仁讨,那個也會導(dǎo)致一些問題)。
第二部分:鎖的分類
鎖根據(jù)不同的性質(zhì)可以分成不同的類实昨。
在WiKiPedia介紹中洞豁,一般的鎖都是建議鎖,也就四每個任務(wù)去訪問公共資源的時候荒给,都需要取得鎖的資訊丈挟,再根據(jù)鎖資訊來確定是否可以存取。若存取對應(yīng)資訊锐墙,鎖的狀態(tài)會改變?yōu)殒i定礁哄,因此其他線程不會訪問該資源,當結(jié)束訪問時溪北,鎖會釋放桐绒,允許其他任務(wù)訪問。有些系統(tǒng)有強制鎖之拨,若未經(jīng)授權(quán)的鎖訪問鎖定的資料茉继,在訪問時就會產(chǎn)生異常。
在iOS中蚀乔,鎖分為遞歸鎖烁竭、條件鎖、分布式鎖吉挣、一般鎖(這里是看著NSLock類里面的分類劃分的)派撕。
對于數(shù)據(jù)庫的鎖分類:
分類方式分類
按鎖的粒度劃分表級鎖、行級鎖睬魂、頁級鎖
按鎖的級別劃分共享鎖终吼、排他鎖
按加鎖方式劃分自動鎖、顯示鎖
按鎖的使用方式劃分樂觀鎖氯哮、悲觀鎖
按操作劃分DML鎖际跪、DDL鎖
這里就不在詳細介紹了,感興趣的大家可以自己查閱相關(guān)資料喉钢。
第三部分:鎖的作用
這個比較通俗來講:就是為了防止在多線程(多任務(wù))的情況下對共享資源(臨界資源)的臟讀或者臟寫姆打。也可以理解為:執(zhí)行多線程時用于強行限制資源訪問的同步機制,即并發(fā)控制中保證互斥的要求肠虽。
第四部分:iOS中鎖的實現(xiàn)
先看看iOS中NSLock類的.h文件幔戏。這里就不在寫上來了。從代碼中可以看出税课,該類分成了幾個子類:NSLock评抚、NSConditionLock豹缀、NSRecursiveLock以及NSCondition。然后有一個NSLocking的協(xié)議:
1
2
3
4
5
6
7@protocol?NSLocking
-?(void)lock;
-?(void)unlock;
@end
這幾個子類都遵循了NSLock的協(xié)議慨代,這里簡單介紹一下其中的幾個方法: 對于tryLock方法,嘗試獲取一個鎖啸如,并且立刻返回Bool值侍匙,YES表示獲取了鎖,NO表示沒有獲取鎖失敗叮雳。 lockBeforeDate:方法想暗,在某個時刻之前獲取鎖,如果獲取成功帘不,則返回YES说莫,NO表示獲取鎖失敗。接下來就讓我們看一下iOS中實現(xiàn)鎖的方式:
方式1 使用NSLock類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26-?(void)nslockDemo?{
NSLock?*myLock?=?[[NSLock?alloc]?init];
_testLock?=?[[TestLock?alloc]?init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
[myLock?lock];
[_testLock?method1];
sleep(5);
[myLock?unlock];
if([myLock?tryLock])?{
NSLog(@"可以獲得鎖");
}else{
NSLog(@"不可以獲得所");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
sleep(1);
if([myLock?tryLock])?{
NSLog(@"---可以獲得鎖");
}else{
NSLog(@"----不可以獲得所");
}
[myLock?lock];
[_testLock?method2];
[myLock?unlock];
});
}
方式2 使用@synchorize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16-?(void)synchronizeDemo?{
_testLock?=?[[TestLock?alloc]?init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
@synchronized?(_testLock)?{
[_testLock?method1];
sleep(5);
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
sleep(1);
@synchronized?(_testLock)?{
[_testLock?method2];
}
});
}
對于@synchorize指令中使用的testLock為該鎖標示寞焙,只有標示相同的時候才滿足鎖的效果储狭。它的優(yōu)點是不用顯式地創(chuàng)建鎖,便可以實現(xiàn)鎖的機制捣郊。但是它會隱式地添加異常處理程序來保護代碼辽狈,該程序在拋出異常的時候自動釋放鎖。
方式3 使用gcd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16-?(void)gcdDemo?{
_testLock?=?[[TestLock?alloc]?init];
dispatch_semaphore_t?semaphore?=?dispatch_semaphore_create(1);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
dispatch_semaphore_wait(semaphore,?DISPATCH_TIME_FOREVER);
[_testLock?method1];
sleep(5);
dispatch_semaphore_signal(semaphore);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
sleep(1);
dispatch_semaphore_wait(semaphore,?DISPATCH_TIME_FOREVER);
[_testLock?method2];
dispatch_semaphore_signal(semaphore);
});
}
方式4 使用phtread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22-?(void)pthreadDemo?{
_testLock?=?[[TestLock?alloc]?init];
__block?pthread_mutex_t?mutex;
pthread_mutex_init(&mutex,?NULL);
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
pthread_mutex_lock(&mutex);
[_testLock?method1];
sleep(5);
pthread_mutex_unlock(&mutex);
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{
sleep(1);
pthread_mutex_lock(&mutex);
[_testLock?method2];
pthread_mutex_unlock(&mutex);
});
}
pthread_mutex_t定義在pthread.h呛牲,所以記得#include刮萌。
3 性能對比
這里簡單寫一個小程序來進行四種方式的性能對比,這里再固定次數(shù)內(nèi)進行了加鎖解鎖娘扩,然后輸出用時着茸,結(jié)果如下(測試1、2執(zhí)行次數(shù)不一樣:測試1 < 測試2):
1
2
3
4
5
6
7
8
9
10
11
12
13
14測試1
2016-11-05?15:27:52.595?LockDemo[4394:202297]?NSLocktimes:0.871843
2016-11-05?15:27:56.335?LockDemo[4394:202297]?synthorizetimes:3.738939
2016-11-05?15:27:56.691?LockDemo[4394:202297]?gcdtimes:0.355344
2016-11-05?15:27:57.328?LockDemo[4394:202297]?pthreadtimes:0.636815
2016-11-05?15:27:57.559?LockDemo[4394:202297]?OSSPinLocktimes:0.231013
2016-11-05?15:27:57.910?LockDemo[4394:202297]?os_unfair_locktimes:0.350615
測試2
2016-11-05?15:30:54.123?LockDemo[4454:205180]?NSLocktimes:1.908103
2016-11-05?15:31:02.112?LockDemo[4454:205180]?synthorizetimes:7.988547
2016-11-05?15:31:02.905?LockDemo[4454:205180]?gcdtimes:0.792113
2016-11-05?15:31:04.372?LockDemo[4454:205180]?pthreadtimes:1.466987
2016-11-05?15:31:04.870?LockDemo[4454:205180]?OSSPinLocktimes:0.497487
2016-11-05?15:31:05.637?LockDemo[4454:205180]?os_unfair_locktimes:0.767569
這里還測試了OSSPinLock(此類已經(jīng)被os_unfair_lock所替代)琐旁。結(jié)果如下: synthorize > NSLock > pthread > gcd > os_unfair_lock >OSSPinLock 這里:
synthorize內(nèi)部會添加異常處理涮阔,所以耗時。
pthread_mutex底層API旋膳,處理能力不錯澎语。
gcd系統(tǒng)封裝的C代碼效果比pthread好。
4 總結(jié)
簡單就介紹這么多验懊。
5 參考文檔:
http://www.liuhaihua.cn/archives/220300.html
https://zh.wikipedia.org/zh-hans/%E9%94%81_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)