ios - 多線程之四:線程鎖

假如我們在功能的實現(xiàn)過程中眨层,類中有一個全局變量锁右,我們創(chuàng)建了多個線程去同時改變或者使用這個變量,會出現(xiàn)什么問題很魂?

線程鎖就是用來解決多線程之間對資源共享的問題扎酷;

思路

在上文《多線程之三》的基礎(chǔ)之上進(jìn)行演示,模仿多個地點進(jìn)行售票的案例遏匆。

代碼展示

1:創(chuàng)建按鈕

    //問題 : 當(dāng)多個線程執(zhí)行某一塊相同代碼法挨,需要線程鎖進(jìn)行保護(hù)
UIButton *btn3 = [UIButton buttonWithType:UIButtonTypeCustom];
btn3.frame = CGRectMake(40, 200, 100, 40);
[btn3 setTitle:@"線程鎖" forState:UIControlStateNormal];
[btn3 setBackgroundColor:[UIColor blueColor]];
[btn3 addTarget:self action:@selector(click_lock) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn3];

2:創(chuàng)建售票的管理對象
TicketManager.h

@interface TicketManager : NSObject
- (void) startSale ;
@end

TicketManager.m
首先做一個擴(kuò)展

  \#define Total 100   //一共一百張票

  @interface TicketManager ()

  @property (nonatomic, assign) int whole;        //總票數(shù)
  @property (nonatomic, assign) int surplus;      //剩余票數(shù)

  @property (nonatomic, strong) NSThread *thread_SH; //子線程, 上海售票點
  @property (nonatomic, strong) NSThread *thread_BJ; //子線程幅聘, 北京售票點
  @property (nonatomic, strong) NSThread *thread_SZ; //子線程凡纳, 深圳售票點

  @end

初始化售賣點

@implementation TicketManager

- (instancetype)init
{
self = [super init];
if (self) {
    self.whole = Total;
    self.surplus = Total;
    
    self.thread_SH = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
    self.thread_SH.name = @"上海售票點";
    
    self.thread_BJ = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
    self.thread_BJ.name = @"北京售票點";
    
    self.thread_SZ = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
    self.thread_SZ.name = @"深圳售票點";
}
return self;
}

實現(xiàn)售賣方法

//售票方法
- (void) sale {

while (true) {
    
    if (self.surplus > 0) {  //當(dāng)還有余票時,就執(zhí)行賣票
        [NSThread sleepForTimeInterval:1];
        self.surplus = self.surplus - 1;
        NSLog(@"%@ 賣出一張票帝蒿,剩余:%d",[NSThread currentThread].name, self.surplus);
    }
}

}

三個地方開始同時售票
//開始賣票
- (void) startSale {
[self.thread_SZ start];
[self.thread_BJ start];
[self.thread_SH start];
}

3:在 viewController 里面創(chuàng)建和使用TicketMananger

@property (nonatomic, strong) TicketManager *ticketManager; //票務(wù)管理

在 viewDidLoad 中初始化

self.ticketManager = [[TicketManager alloc] init];

在 click_lock 中啟動賣票

 NSLog(@"開始賣票");
[self.ticketManager startSale];

4:開始執(zhí)行荐糜,查看打印結(jié)果

售票打印.png

根據(jù)日志分析:非常明顯剩余票數(shù)不正確。

接下來我們引入鎖的概念來解決這個問題陵叽。簡單說明下鎖是什么概念呢狞尔?咱們可以先這樣理解:當(dāng)我在獨自使用一個房間的時候丛版,不希望別人同時使用和打擾巩掺,這樣呢,我們也就可以先對該房間加上鎖页畦,然后再使用胖替,在使用完成之后,該房間不歸我使用了,我就解開鎖独令,以方便其他人使用端朵、
線程鎖有三種方式:
1 : @synchronized
使用方法:將要保護(hù)起來的代碼塊添加到 @synchronized 的括號中包裹起來

//線程鎖的第一種方式 :@synchronized
    @synchronized (self) {
        if (self.surplus > 0) {  //當(dāng)還有余票時,就執(zhí)行賣票
            [NSThread sleepForTimeInterval:1];
            self.surplus = self.surplus - 1;
            NSLog(@"%@ 賣出一張票燃箭,剩余:%d",[NSThread currentThread].name, self.surplus);
        }
    }

2:NSCondition
使用方法:創(chuàng)建了 NSCondition 對象冲呢,將保護(hù)起來的代碼塊使用 lock 和 unlock 進(jìn)行前后包裹;

//線程鎖的第二種方式:NSCondition
    if (!self.condition) {
        self.condition = [[NSCondition alloc] init];
    }
    [self.condition lock];
    if (self.surplus > 0) {  //當(dāng)還有余票時招狸,就執(zhí)行賣票
        [NSThread sleepForTimeInterval:1];
        self.surplus = self.surplus - 1;
        NSLog(@"%@ 賣出一張票敬拓,剩余:%d",[NSThread currentThread].name, self.surplus);
    }
    [self.condition unlock];

3:NSLock
使用方法:創(chuàng)建了 NSLock 對象,將保護(hù)起來的代碼塊使用 lock 和 unlock 進(jìn)行前后包裹裙戏;

//線程鎖的第三種方式:NSLock
    if (!self.lock) {
        self.lock = [[NSLock alloc] init];
    }
    [self.lock lock];
    if (self.surplus > 0) {  //當(dāng)還有余票時乘凸,就執(zhí)行賣票
        [NSThread sleepForTimeInterval:1];
        self.surplus = self.surplus - 1;
        NSLog(@"%@ 賣出一張票,剩余:%d",[NSThread currentThread].name, self.surplus);
    }
    [self.lock unlock];

在我們使用了以上三種線程鎖之后的打印結(jié)果是怎么樣的呢累榜?

線程鎖的打印

可以看出打印的結(jié)果是健康和良性的营勤;

至此,線程鎖的使用先告一段落壹罚,我會再后期詳細(xì)給出三種線程鎖的詳細(xì)特性和使用場景葛作。敬請期待 ~~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猖凛,隨后出現(xiàn)的幾起案子进鸠,更是在濱河造成了極大的恐慌,老刑警劉巖形病,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件客年,死亡現(xiàn)場離奇詭異,居然都是意外死亡漠吻,警方通過查閱死者的電腦和手機(jī)量瓜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來途乃,“玉大人绍傲,你說我怎么就攤上這事∷9玻” “怎么了烫饼?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長试读。 經(jīng)常有香客問我杠纵,道長,這世上最難降的妖魔是什么钩骇? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任比藻,我火速辦了婚禮铝量,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘银亲。我一直安慰自己慢叨,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布务蝠。 她就那樣靜靜地躺著拍谐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪馏段。 梳的紋絲不亂的頭發(fā)上赠尾,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機(jī)與錄音毅弧,去河邊找鬼气嫁。 笑死,一個胖子當(dāng)著我的面吹牛够坐,可吹牛的內(nèi)容都是我干的寸宵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼元咙,長吁一口氣:“原來是場噩夢啊……” “哼梯影!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起庶香,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤甲棍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赶掖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體感猛,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年奢赂,在試婚紗的時候發(fā)現(xiàn)自己被綠了陪白。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡膳灶,死狀恐怖咱士,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轧钓,我是刑警寧澤序厉,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站毕箍,受9級特大地震影響弛房,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霉晕,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一庭再、第九天 我趴在偏房一處隱蔽的房頂上張望捞奕。 院中可真熱鬧牺堰,春花似錦拄轻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筏养,卻和暖如春斧抱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背渐溶。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工辉浦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茎辐。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓宪郊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拖陆。 傳聞我的和親對象是個殘疾皇子弛槐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

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