OC底層原理二十九:NSLock、NSCondition辽话、NSConditionLock

OC底層原理 學(xué)習(xí)大綱

上一節(jié)對(duì)鎖家族@synchronized進(jìn)行源碼解析固耘,本節(jié)將對(duì)鎖家族的其他2位NSLockNSCondition進(jìn)行源碼分析题篷。

  • 鎖家族全家福(耗時(shí)圖):
    image.png
  1. NSLock應(yīng)用與源碼
  2. NSLock、NSRecursiveLock厅目、@synchronized三者的區(qū)別
  3. NSCondition
  4. NSConditionLock

1. NSLock

  • 測(cè)試代碼
@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *testArray;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self demo];
}

- (void)demo {
    NSLog(@"123");
    self.testArray = [NSMutableArray array];
    NSLock * lock = [[NSLock alloc] init]; // 創(chuàng)建
    for (int i = 0; i < 20000; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [lock lock]; // 加鎖
            self.testArray = [NSMutableArray array];
            [lock unlock]; // 解鎖
        });
    }
}
@end
  • 進(jìn)入NSLock番枚,可以看到它遵循NSLocking協(xié)議:
@protocol NSLocking

- (void)lock;
- (void)unlock;

@end

@interface NSLock : NSObject <NSLocking> { ... }
 ... 
@end

@interface NSConditionLock : NSObject <NSLocking>   { ... }
 ... 
@end

@interface NSRecursiveLock : NSObject <NSLocking>  { ... }
 ... 
@end

@interface NSCondition : NSObject <NSLocking>  { ... }
 ... 
@end
  • NSLocking協(xié)議包含lockunlock兩個(gè)方法法严。
  • NSLockNSConditionLock葫笼、 NSRecursiveLock深啤、 NSCondition都遵循NSLocking協(xié)議
  • 現(xiàn)在,我們開(kāi)始尋找lock源碼的出處:
  • 方法一: 在代碼[lock lock]加鎖處中路星,加入斷點(diǎn)溯街,打開(kāi)debug匯編模式,一步步執(zhí)行洋丐,查詢?cè)创a的出處: 很遺憾呈昔,發(fā)現(xiàn)找不到

  • 方法二: 直接斷點(diǎn)進(jìn)不去,那我們運(yùn)行到斷點(diǎn)處后友绝,加入lock符號(hào)斷點(diǎn)堤尾,再運(yùn)行代碼,發(fā)現(xiàn)找到了迁客,在Foundation庫(kù)中執(zhí)行的:

    image.png

  • 可是Foudation庫(kù)是未開(kāi)源庫(kù)郭宝,我們無(wú)法獲取源碼坛梁。但是swift開(kāi)源語(yǔ)言巧勤。我們可以參考swift Foudation庫(kù)

  • 打開(kāi)swift Foundation庫(kù)桃犬,搜索class NSLock:

    image.png

我們發(fā)現(xiàn):

  • 1.init中初始化了pthread_mutex
    1. lockunlock實(shí)際都是調(diào)用pthread_mutex相對(duì)于的lockunlock函數(shù)

順便探究NSRecursiveLock卜范、NSConditionNSConditionLock

  • 發(fā)現(xiàn)NSRecursiveLock衔统、NSCodition也是基于pthread_mutex封裝的,但:
  • NSRecursiveLockNSLock多了一層遞歸邏輯
  • NSCoditionNSLock多了一層pthread_con_init條件鎖海雪。
  • NSConditionLock是在NSCondition的基礎(chǔ)上進(jìn)行的再次封裝缰冤。
NSRecursiveLock
NSCondition

NSConditionLock

結(jié)論:

    1. 必須調(diào)用init方法(new內(nèi)部也調(diào)用了init方法),因?yàn)?code>init會(huì)完成底層pthread_mutex相關(guān)鎖初始化
    1. 所有遵循NSLocking協(xié)議的類喳魏,底層都是基于pthread_mutex鎖來(lái)實(shí)現(xiàn)的,只是封裝深度不同怀薛。
    1. NSLock性能接近pthread_mutex刺彩,而pthread_mutex(recursive)NSRecursiveLock枝恋、NSCondition创倔、NSConditionLock耗時(shí)一個(gè)比一個(gè),就是由對(duì)pthread_mutex封裝深度決定的焚碌。

2. NSLock畦攘、NSRecursiveLock、@synchronized三者的區(qū)別

我們通過(guò)一個(gè)案例來(lái)進(jìn)行分析對(duì)比

  • 案例:循環(huán)生成多個(gè)全局隊(duì)列的異步線程十电,每個(gè)線程內(nèi)聲明block(testMethod)-> 實(shí)現(xiàn)block -> 調(diào)用block -> 嵌套調(diào)用block(遞歸調(diào)用)

  • 要求: 分別使用NSLock知押、NSRecursiveLock叹螟、@synchronized實(shí)現(xiàn)讀寫安全

- (void)demo{
    for (int i= 0; i<10; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           
            static void (^testMethod)(int);// 1. 聲明
            
            testMethod = ^(int value){  // 2. 實(shí)現(xiàn)Block塊
                if (value > 0) {
                  NSLog(@"current value = %d",value);
                  testMethod(value - 1); // 4. 嵌套調(diào)用block
                }
            };
            
            testMethod(10); // 3.調(diào)用block
        });
    }
}

2.1 使用NSLock:

必須在Block實(shí)現(xiàn)前加鎖,在調(diào)用后解鎖

image.png

相關(guān)實(shí)踐:

  1. 調(diào)用前加鎖: 死鎖
    image.png
  • 僅在第一次進(jìn)入block時(shí)打印了一次台盯,后面就死鎖了罢绽。
    (一直lock加鎖,而沒(méi)有unlock解鎖導(dǎo)致的)

2.調(diào)用后加鎖: 無(wú)效鎖

image.png

  • 打印結(jié)果完全無(wú)序静盅,的作用完全消失
    (想想都知道良价,block執(zhí)行完了,你再上鎖蒿叠,有啥用明垢,了一堆寂寞 ?? )
  • 所以如果使用NSLock鎖,必須在聲明前加鎖調(diào)用后解鎖市咽,才能解決數(shù)據(jù)讀寫安全問(wèn)題痊银。

?? NSLock鎖,只鎖了當(dāng)前線程魂务,當(dāng)我們使用異步多線程操作時(shí)曼验,可能出現(xiàn)線程相互等待死鎖的情況

2.2 使用NSRecursiveLock

  • 聲明前加鎖調(diào)用后解鎖是正確的粘姜。

    image.png

  • 但由于它具備遞歸特性鬓照,我們?cè)?code>block內(nèi)部的遞歸前當(dāng)前線程也打印正常孤紧,但是其他線程堵塞豺裆。

    image.png

  • 當(dāng)我們?nèi)サ?code>for循環(huán),僅保持一個(gè)異步線程号显,在block內(nèi)部遞歸前后分別加鎖解鎖臭猜,打印正常:

    image.png

這是因?yàn)?code>NSRecursiveLock的遞歸特性。內(nèi)部任務(wù)是遞歸持有的押蚤,所以不會(huì)死鎖蔑歌。

image.png

2.3 @synchronized

  • @synchronized最簡(jiǎn)單,直接將block內(nèi)部代碼包裹起來(lái)揽碘,就可以實(shí)現(xiàn)數(shù)據(jù)讀寫安全

    image.png

  • 關(guān)于@synchronized的內(nèi)部結(jié)構(gòu)次屠,我們上一節(jié)專門分析了。

  • @synchronized能對(duì)記錄被鎖對(duì)象所有線程雳刺,每個(gè)線程內(nèi)部都是遞歸持有任務(wù)的劫灶。所以在異步多線程中,它既不用擔(dān)心遞歸造成的鎖釋放問(wèn)題掖桦,也不需要關(guān)心線程間通信問(wèn)題本昏。

NSLock、NSRecursiveLock枪汪、@synchronized三者的區(qū)別

  • NSLock:

    1. 需要手動(dòng)創(chuàng)建釋放涌穆,需要在準(zhǔn)確的時(shí)機(jī)進(jìn)行相應(yīng)操作怔昨。
    2. 僅鎖住當(dāng)前線程當(dāng)前任務(wù)無(wú)法自動(dòng)實(shí)現(xiàn)線程間通訊遞歸問(wèn)題蒲犬。
      (上述NSLock代碼實(shí)際上沒(méi)解決遞歸問(wèn)題朱监,只是野蠻的代碼最外層上了一把大鎖無(wú)視遞歸內(nèi)部層級(jí)
  • NSRecursiveLock:

    1. 需要手動(dòng)創(chuàng)建釋放原叮,需要在準(zhǔn)確的時(shí)機(jī)進(jìn)行相應(yīng)操作赫编。
    2. 僅鎖住當(dāng)前線程所有任務(wù)無(wú)法自動(dòng)實(shí)現(xiàn)線程間通訊奋隶,但可以解決遞歸問(wèn)題擂送。
      (與NSLock不同,NSRecursiveLock是在遞歸時(shí)唯欣,每層加鎖解鎖嘹吨。對(duì)鎖的控制更為精確
  • @synchronized:

    1. 只需將需要鎖代碼都放在作用域內(nèi),確定被鎖對(duì)象(被鎖對(duì)象決定了鎖的生命周期)境氢,@synchronized就可以做到自動(dòng)創(chuàng)建釋放蟀拷。
    1. 被鎖對(duì)象所有線程所有任務(wù)自動(dòng)實(shí)現(xiàn)線程間通訊萍聊,可以解決遞歸問(wèn)題问芬。
      (內(nèi)部邏輯為: 被鎖對(duì)象可持有多個(gè)線程每個(gè)線程遞歸持有多個(gè)任務(wù))

所以我們日常使用時(shí)寿桨,盡管@synchronized耗時(shí)較大此衅,但是它使用非常簡(jiǎn)單,根本不需要處理各種異常情況亭螟,也不需要手動(dòng)釋放挡鞍。便捷性安全性非常好

3. NSCondition

NSCondition的對(duì)象實(shí)際上是作為一個(gè)和一個(gè)線程檢查器:

  • : 當(dāng)檢查條件成立時(shí)预烙,保護(hù)數(shù)據(jù)源
  • 線程檢查器根據(jù)條件判斷是否繼續(xù)運(yùn)行線程(線程是否阻塞)

方法:

  • [condition lock]: 加鎖
    (一般用于多線程同時(shí)訪問(wèn)墨微、修改同一個(gè)數(shù)據(jù)源時(shí),保證同一時(shí)間內(nèi)數(shù)據(jù)源只能被訪問(wèn)扁掸、修改一次欢嘿,其他線程的命令需要在lock外等待,只有unlock后也糊,才可訪問(wèn)
  • [condition unlock]: 解鎖(與lock配對(duì)使用)
  • [condition wait]:當(dāng)前線程處于等待狀態(tài)
  • [condition signal]:CPU發(fā)信號(hào)告訴所有線程不用再等待,可以繼續(xù)執(zhí)行羡宙。
  • 測(cè)試案例:
    2個(gè)生產(chǎn)者2個(gè)消費(fèi)者狸剃,各自生產(chǎn)和消費(fèi)各50次。當(dāng)消費(fèi)者購(gòu)買時(shí)狗热,沒(méi)貨排隊(duì)等待钞馁,有貨賣貨,一次只能一個(gè)人買虑省, 每當(dāng)生產(chǎn)者生產(chǎn)一個(gè)貨物時(shí),都會(huì)廣播告訴所有等待消費(fèi)者僧凰,進(jìn)行繼續(xù)購(gòu)買探颈。
    這樣保障貨品數(shù)據(jù)安全(有貨才能賣,一次賣一個(gè)训措,沒(méi)貨就等待)
@interface ViewController ()
@property (nonatomic, assign) NSUInteger ticketCount;
@property (nonatomic, strong) NSCondition *testCondition;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.ticketCount = 0;
    [self demo];
}

- (void)demo{
    
    _testCondition = [[NSCondition alloc] init];
    
    //創(chuàng)建生產(chǎn)-消費(fèi)者
    for (int i = 0; i < 50; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self producer]; // 生產(chǎn)者
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self consumer]; // 消費(fèi)者
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self consumer]; // 消費(fèi)者
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self producer]; // 生產(chǎn)者
        });
    }
}

- (void)producer{
    [_testCondition lock]; // 操作的多線程影響
    self.ticketCount = self.ticketCount + 1;
    NSLog(@"生產(chǎn)一個(gè) 現(xiàn)有 count %zd",self.ticketCount);
    [_testCondition signal]; // 發(fā)送信號(hào)
    [_testCondition unlock];
}

- (void)consumer{
 
     [_testCondition lock];  // 操作的多線程影響
    if (self.ticketCount == 0) {
        NSLog(@"等待 count %zd",self.ticketCount);
        [_testCondition wait]; // 線程等待
    }
    //注意消費(fèi)行為伪节,要在等待條件判斷之后
    self.ticketCount -= 1;
    NSLog(@"消費(fèi)一個(gè) 還剩 count %zd ",self.ticketCount);
     [_testCondition unlock];
}
@end
  • 打印結(jié)果:(生產(chǎn)消費(fèi)數(shù)據(jù)是安全的)


    image.png

但是NSCondition使用非常麻煩,需要在合適的地方手動(dòng)加鎖绩鸣、等待怀大、發(fā)送信號(hào)釋放
于是基于NSCondition呀闻,出現(xiàn)了NSConditionLock

4. NSConditionLock

NSConditionLock是一把化借,一旦一個(gè)線程獲得其他線程一定等待捡多。

方法:

  • [xxx lock]: 加鎖

    • 如果沒(méi)有其他線程獲得(不需要判斷內(nèi)部的condition)蓖康,那他能執(zhí)行后續(xù)代碼,同時(shí)設(shè)置當(dāng)前線程獲得垒手。
    • 如果已經(jīng)其他線程獲得(可能是條件鎖蒜焊,或者無(wú)條件鎖),則等待淫奔,直到其他線程解鎖
  • [xxx lockWhenCondition: A條件]:

    • [xxx lock]基礎(chǔ)上山涡,沒(méi)有其他線程獲得,且內(nèi)部condition條件滿足A條件時(shí)唆迁,會(huì)執(zhí)行后續(xù)代碼并讓當(dāng)前線程獲得鸭丛。否則依舊是等待
  • [xxx unlockWithCondition: A條件]:釋放

    • 內(nèi)部的condition設(shè)置為A條件,并broadcast廣播告訴所有等待的線程唐责。
  • return = [xxx lockWhenCondition: A條件 beforeDate: A時(shí)間]:

    • 沒(méi)有其他線程獲得鳞溉,且滿足A條件,且在A時(shí)間之前鼠哥,可以執(zhí)行后續(xù)代碼并讓當(dāng)前線程獲得熟菲。
    • 返回值為NO,表示沒(méi)有改變鎖的狀態(tài)
  • condition整數(shù)朴恳,內(nèi)部通過(guò)整數(shù)比較條件

  • 通過(guò)下面案例分析:
- (void)demo{

    NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
         [conditionLock lockWhenCondition:1]; // conditoion = 1 內(nèi)部 Condition 匹配
        NSLog(@"線程 1");
         [conditionLock unlockWithCondition:0]; // 解鎖并把conditoion設(shè)置為0
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
       
        [conditionLock lockWhenCondition:2]; // conditoion = 2 內(nèi)部 Condition 匹配
        sleep(0.1);
        NSLog(@"線程 2");
        [conditionLock unlockWithCondition:1]; // 解鎖并把conditoion設(shè)置為1
    });
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       
       [conditionLock lock]; 
       NSLog(@"線程 3");
       [conditionLock unlock];
    });
}
  • 打印結(jié)果:


    image.png

分析:

  1. 有三個(gè)并行隊(duì)列+異步函數(shù)抄罕,分別處理三個(gè)任務(wù),三個(gè)任務(wù)的執(zhí)行順序無(wú)序于颖。
    并行隊(duì)列+異步線程是的執(zhí)行順序是不固定的呆贿,取決于任務(wù)資源大小cpu的調(diào)度
  2. 我們init時(shí),將condition設(shè)置為2。
    • 任務(wù)1: 必須當(dāng)前線程沒(méi)被鎖做入,且condition1時(shí)冒晰,我才加鎖執(zhí)行后面代碼
    • 任務(wù)2: 必須當(dāng)前線程沒(méi)被鎖竟块,且condition2時(shí)壶运,我才加鎖并執(zhí)行后面代碼
    • 任務(wù)3: 必須當(dāng)前線程沒(méi)被鎖浪秘,我可以加鎖并執(zhí)行后面代碼蒋情。

所以任務(wù)3執(zhí)行時(shí)期不確定,只要當(dāng)前線程沒(méi)被鎖秫逝,隨時(shí)都可以恕出。 任務(wù)1一定在任務(wù)2后面

  • 因?yàn)?code>condition初始值為2,只有任務(wù)2滿足條件违帆,任務(wù)2執(zhí)行完后浙巫,將condition設(shè)置為1,并broadcast廣播給所有等待的線程刷后。
  • 此時(shí)正在等待任務(wù)1的線程收到廣播的畴,檢查任務(wù)1滿足條件尝胆,任務(wù)1執(zhí)行完后丧裁,將condition設(shè)置為0,并broadcast廣播給所有等待的線程含衔。
  • Swift Foundation源碼中搜索NSConditionLock煎娇,可以看到循環(huán)檢查線程、條件上鎖過(guò)程:
    image.png

感興趣的贪染,我們可以匯編驗(yàn)證部分流程
(匯編機(jī)器執(zhí)行代碼缓呛,是最準(zhǔn)確執(zhí)行順序找不到源碼時(shí)杭隙,只有它才是最有效探索路徑)

(PS: 匯編確實(shí)很難懂哟绊,這里只是簡(jiǎn)單介紹一下部分流程,主要是思路的拓寬)

  • 簡(jiǎn)化測(cè)試代碼:
- (void)demo{
   
   NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
   
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
       [conditionLock lockWhenCondition:2]; // conditoion = 2 內(nèi)部 Condition 匹配
       NSLog(@"線程 2");
       [conditionLock unlockWithCondition:1]; // 解鎖并把conditoion設(shè)置為1
   });
}
  • lockWhenCondition加上斷點(diǎn)痰憎,打開(kāi)匯編模式:
image.png

image.png
  • 運(yùn)行代碼票髓,執(zhí)行到斷點(diǎn)處,再加入lockWhenCondition:符號(hào)斷點(diǎn):(注意:冒號(hào)不能少铣耘,前后不能有空格)洽沟,再運(yùn)行代碼

    image.png

  • lockWhenCondition:beforeDate:一行加斷點(diǎn)運(yùn)行至此處蜗细,讀取參數(shù)玲躯,發(fā)現(xiàn)beforeDate的默認(rèn)值是distantFuture

    image.png

  • 加入lockWhenCondition:beforeDate:符號(hào)斷點(diǎn),運(yùn)行代碼,進(jìn)入到該函數(shù)內(nèi):

    image.png

  • 發(fā)現(xiàn)首先調(diào)了lock函數(shù)跷车,我們加入lock斷點(diǎn),運(yùn)行代碼橱野,發(fā)現(xiàn)內(nèi)部是NSCondition執(zhí)行了lock方法:

    image.png

回到上一頁(yè)朽缴,我們?cè)?code>pthread_equal下一行加入斷點(diǎn),運(yùn)行代碼水援。打印相應(yīng)值:

image.png

  • pthread_equal檢查線程是否存在密强,true:跳到0x7fff207ef545false:比較r15rbx偏移0x10位蜗元。
    這里實(shí)際就是檢查線程是否存在或渤,如果不存在,再檢查condition是否相等奕扣。才進(jìn)行后續(xù)操作

... 大概思路就是這樣... 講個(gè)思路就行薪鹦。 真正的匯編探索,還需要很大的基本功海量訓(xùn)練惯豆。

關(guān)于鎖的探索池磁,到此為止。 其他類型的鎖楷兽,可以用類似方式探索研究地熄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芯杀,隨后出現(xiàn)的幾起案子端考,更是在濱河造成了極大的恐慌,老刑警劉巖揭厚,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件却特,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棋弥,警方通過(guò)查閱死者的電腦和手機(jī)核偿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)顽染,“玉大人漾岳,你說(shuō)我怎么就攤上這事》勰” “怎么了尼荆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)唧垦。 經(jīng)常有香客問(wèn)我捅儒,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任巧还,我火速辦了婚禮鞭莽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘麸祷。我一直安慰自己澎怒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布阶牍。 她就那樣靜靜地躺著喷面,像睡著了一般。 火紅的嫁衣襯著肌膚如雪走孽。 梳的紋絲不亂的頭發(fā)上惧辈,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音磕瓷,去河邊找鬼盒齿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛生宛,可吹牛的內(nèi)容都是我干的县昂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼陷舅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼倒彰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起莱睁,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤待讳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后仰剿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體创淡,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年南吮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琳彩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡部凑,死狀恐怖露乏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涂邀,我是刑警寧澤瘟仿,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站比勉,受9級(jí)特大地震影響劳较,放射性物質(zhì)發(fā)生泄漏驹止。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一观蜗、第九天 我趴在偏房一處隱蔽的房頂上張望臊恋。 院中可真熱鬧,春花似錦墓捻、人聲如沸捞镰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至践樱,卻和暖如春厂画,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拷邢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工袱院, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瞭稼。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓忽洛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親环肘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子欲虚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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

  • 目錄:1.為什么要線程安全2.多線程安全隱患分析3.多線程安全隱患的解決方案4.鎖的分類-13種鎖4.1.1OSS...
    二斤寂寞閱讀 1,184評(píng)論 0 3
  • 概念 自旋鎖: 線程反復(fù)檢查鎖變量是否可用。由于線程在這一過(guò)程中保持執(zhí)行悔雹, 因此是一種忙等待复哆。一旦獲取了自旋鎖,線...
    MonKey_Money閱讀 850評(píng)論 2 1
  • 了解鎖的機(jī)制會(huì)有助于項(xiàng)目開(kāi)發(fā)腌零,從而避免項(xiàng)目中多個(gè)線程訪問(wèn)同一塊資源引發(fā)數(shù)據(jù)混亂的問(wèn)題梯找。 一 概念 鎖的歸類 基本...
    yan0_0閱讀 291評(píng)論 0 2
  • 回顧之前 前文講到多線程原理,線程安全益涧、線程阻塞锈锤、線程使用等;這節(jié)我們來(lái)分析一下有關(guān)線程安全的一部分:鎖闲询,線程鎖久免。...
    孜孜不倦_閑閱讀 897評(píng)論 0 2
  • 久違的晴天,家長(zhǎng)會(huì)嘹裂。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí)妄壶,離放學(xué)已經(jīng)沒(méi)多少時(shí)間了。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)寄狼。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22