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:开始执行,查看打印结果
根据日志分析:非常明显剩余票数不正确。
接下来我们引入锁的概念来解决这个问题。简单说明下锁是什么概念呢?咱们可以先这样理解:当我在独自使用一个房间的时候,不希望别人同时使用和打扰,这样呢,我们也就可以先对该房间加上锁,然后再使用,在使用完成之后,该房间不归我使用了,我就解开锁,以方便其他人使用、
线程锁有三种方式:
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];
在我们使用了以上三种线程锁之后的打印结果是怎么样的呢?
可以看出打印的结果是健康和良性的;
至此,线程锁的使用先告一段落,我会再后期详细给出三种线程锁的详细特性和使用场景。敬请期待 ~~~~
- iOS
- iOS
- IOS
- iOS
- iOS
- IOS
- ios
- iOS
- iOS
- IOS
- iOS
- ios
- ios ~~~~~
- ios
- IOS
- IOS
- IOS
- ios
- SpringCloud服务注册中心比较:Consul vs Zookeeper vs Etcd vs Eureka
- Invalid bound statement (not found): xxx.xxxx.method解决办法
- tableViewCell列表点击展开显示二级列表
- leetcode 136. Single Number
- kafka详解
- ios
- xml命名空间等
- 最短路径—Dijkstra算法和Floyd算法
- iOS 键盘回收事件的处理,一句话搞定
- jQuery给input赋值
- 树形结构过滤敏感词
- Dagger 2应用于Android的完美扩展库-dagger.android
- AspectJ 开发
- 上传漏洞小结