ios

来源:互联网 发布:vb中csng是什么意思 编辑:程序博客网 时间:2024/05/29 19:46

假如我们在功能的实现过程中,类中有一个全局变量,我们创建了多个线程去同时改变或者使用这个变量,会出现什么问题?

线程锁就是用来解决多线程之间对资源共享的问题;

思路

在上文《多线程之三》的基础之上进行演示,模仿多个地点进行售票的案例。

代码展示

1:创建按钮

    //问题 : 当多个线程执行某一块相同代码,需要线程锁进行保护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:创建售票的管理对象
TicketManager.h

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

TicketManager.m
首先做一个扩展

  \#define Total 100   //一共一百张票  @interface TicketManager ()  @property (nonatomic, assign) int whole;        //总票数  @property (nonatomic, assign) int surplus;      //剩余票数  @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;}

实现售卖方法

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

while (true) {    if (self.surplus > 0) {  //当还有余票时,就执行卖票        [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 里面创建和使用TicketMananger

@property (nonatomic, strong) TicketManager *ticketManager; //票务管理

在 viewDidLoad 中初始化

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

在 click_lock 中启动卖票

 NSLog(@"开始卖票");[self.ticketManager startSale];

4:开始执行,查看打印结果

售票打印.png

根据日志分析:非常明显剩余票数不正确。

接下来我们引入锁的概念来解决这个问题。简单说明下锁是什么概念呢?咱们可以先这样理解:当我在独自使用一个房间的时候,不希望别人同时使用和打扰,这样呢,我们也就可以先对该房间加上锁,然后再使用,在使用完成之后,该房间不归我使用了,我就解开锁,以方便其他人使用、
线程锁有三种方式:
1 : @synchronized
使用方法:将要保护起来的代码块添加到 @synchronized 的括号中包裹起来

//线程锁的第一种方式 :@synchronized    @synchronized (self) {        if (self.surplus > 0) {  //当还有余票时,就执行卖票            [NSThread sleepForTimeInterval:1];            self.surplus = self.surplus - 1;            NSLog(@"%@ 卖出一张票,剩余:%d",[NSThread currentThread].name, self.surplus);        }    }

2:NSCondition
使用方法:创建了 NSCondition 对象,将保护起来的代码块使用 lock 和 unlock 进行前后包裹;

//线程锁的第二种方式:NSCondition    if (!self.condition) {        self.condition = [[NSCondition alloc] init];    }    [self.condition lock];    if (self.surplus > 0) {  //当还有余票时,就执行卖票        [NSThread sleepForTimeInterval:1];        self.surplus = self.surplus - 1;        NSLog(@"%@ 卖出一张票,剩余:%d",[NSThread currentThread].name, self.surplus);    }    [self.condition unlock];

3:NSLock
使用方法:创建了 NSLock 对象,将保护起来的代码块使用 lock 和 unlock 进行前后包裹;

//线程锁的第三种方式:NSLock    if (!self.lock) {        self.lock = [[NSLock alloc] init];    }    [self.lock lock];    if (self.surplus > 0) {  //当还有余票时,就执行卖票        [NSThread sleepForTimeInterval:1];        self.surplus = self.surplus - 1;        NSLog(@"%@ 卖出一张票,剩余:%d",[NSThread currentThread].name, self.surplus);    }    [self.lock unlock];

在我们使用了以上三种线程锁之后的打印结果是怎么样的呢?

线程锁的打印

可以看出打印的结果是健康和良性的;

至此,线程锁的使用先告一段落,我会再后期详细给出三种线程锁的详细特性和使用场景。敬请期待 ~~~~

0 0