對象鎖:代碼為[臨界區(qū):共同訪問一段代碼]synchronized(Object)語句指定的對象進(jìn)行加鎖
示例:
//主線程中
NSLock *lock = [[NSLock alloc] init];
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
NSLog(@"線程1");
sleep(2);
[lock unlock];
NSLog(@"線程1解鎖成功");
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);//以保證讓線程2的代碼后執(zhí)行
[lock lock];
NSLog(@"線程2");
[lock unlock];
});
2016-08-19 14:23:09.659 ThreadLockControlDemo[1754:129663] 線程1
2016-08-19 14:23:11.663 ThreadLockControlDemo[1754:129663] 線程1解鎖成功
2016-08-19 14:23:11.665 ThreadLockControlDemo[1754:129659] 線程2
NSLock的執(zhí)行原理:
線程 1 中的 lock 鎖上了闷祥,所以線程 2 中的 lock 加鎖失敗傲诵,阻塞線程 2拴竹,但 2 s 后線程 1 中的 lock 解鎖,線程 2 就立即加鎖成功座泳,執(zhí)行線程 2 中的后續(xù)代碼。
查到的資料顯示互斥鎖會使得線程阻塞挑势,阻塞的過程又分兩個階段潮饱,第一階段是會先空轉(zhuǎn),可以理解成跑一個 while 循環(huán)啦扬,不斷地去申請加鎖缕溉,在空轉(zhuǎn)一定時間之后证鸥,線程會進(jìn)入 waiting 狀態(tài),此時線程就不占用CPU資源了泉褐,等鎖可用的時候鸟蜡,這個線程會立即被喚醒揉忘。
所以如果將上面線程 1 中的 sleep(2); 改成 sleep(10); 輸出的結(jié)果會變成
2016-08-19 14:25:16.226 ThreadLockControlDemo[1773:131824] 線程1
2016-08-19 14:25:26.231 ThreadLockControlDemo[1773:131831] 線程2
2016-08-19 14:25:26.231 ThreadLockControlDemo[1773:131824] 線程1解鎖成功
從上面的兩個輸出結(jié)果可以看出泣矛,線程 2 lock 的第一秒您朽,是一直在輪詢請求加鎖的,因為輪詢有時間間隔哗总,所以 ”線程 2“ 的輸出晚于 ”線程 1 解鎖成功“讯屈,但線程 2 lock 的第九秒,是當(dāng)鎖可用的時候具壮,立即被喚醒,所以 ”線程 2“ 的輸出早于 ”線程 1 解鎖成功“。多做了幾次試驗炮赦,發(fā)現(xiàn)輪詢 1 秒之后,線程會進(jìn)入 waiting 狀態(tài)性芬。
//主線程中
NSLock *lock = [[NSLock alloc] init];
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
NSLog(@"線程1");
sleep(10);
[lock unlock];
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);//以保證讓線程2的代碼后執(zhí)行
if ([lock tryLock]) { //嘗試加鎖
NSLog(@"線程2");
[lock unlock];
} else {
NSLog(@"嘗試加鎖失敗");
}
});
2016-08-19 11:42:54.433 ThreadLockControlDemo[1256:56857] 線程1
2016-08-19 11:42:55.434 ThreadLockControlDemo[1256:56861] 嘗試加鎖失敗
由上面的結(jié)果可得知植锉,tryLock 并不會阻塞線程俊庇。[lock tryLock] 能加鎖返回 YES辉饱,不能加鎖返回 NO彭沼,然后都會執(zhí)行后續(xù)代碼姓惑。
如果將 [lock tryLock] 替換成
[lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:10]
的話于毙,則會返回 YES乘寒,輸出 “線程 2“,lockBeforeDate: 方法會在所指定 Date 之前嘗試加鎖烂翰,會阻塞線程甘耿,如果在指定時間之前都不能加鎖佳恬,則返回 NO捏境,指定時間之前能加鎖垫言,則返回 YES筷频。
@protocol NSLocking
- (void)lock;//加鎖
- (void)unlock;//解鎖
@end
@interface NSLock : NSObject <NSLocking> {
@private
void *_priv;
}
//嘗試加鎖凛捏,不會阻塞線程坯癣。true則加鎖成功示罗,false則失敗窒所,說明其他線程在加鎖中這個方法無論如何都會立即返回吵取。
- (BOOL)tryLock;
//嘗試在指定NSDate之前加鎖,會阻塞線程脯倒。true則加鎖成功,false則失敗捺氢,說明其他線程在加鎖中這個方法無論如何都會立即返回藻丢。在拿不到鎖時不會一直在那等待。
- (BOOL)lockBeforeDate:(NSDate *)limit;
//name 是用來標(biāo)識用的
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@end