NSThread(II)
非线程安全
//初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
- (void)initTicketStatusNotSave {
// 1. 设置剩余火车票为 50
self.ticketSurplusCount = ; // 2. 设置北京火车票售卖窗口的线程
self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];
self.ticketSaleWindow1.name = @"北京火车票售票窗口"; // 3. 设置上海火车票售卖窗口的线程
self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];
self.ticketSaleWindow2.name = @"上海火车票售票窗口"; // 4. 开始售卖火车票
[self.ticketSaleWindow1 start];
[self.ticketSaleWindow2 start]; } /**
* 售卖火车票(非线程安全)
*/
- (void)saleTicketNotSafe {
while () {
//如果还有票,继续售卖
if (self.ticketSurplusCount > ) {
self.ticketSurplusCount --;
NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
[NSThread sleepForTimeInterval:0.2];
}
//如果已卖完,关闭售票窗口
else {
NSLog(@"所有火车票均已售完");
break;
}
}
}
打印结果:
<-------------------------NSThread线程结束-------------------------- ::34.640134+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-->
-- ::37.602762+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::39.144970+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::39.144970+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::40.939316+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::40.939316+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::42.343211+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::42.343219+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::43.646726+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::43.646728+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::45.168354+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::45.168361+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::47.232723+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::47.232735+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::49.086100+ StruggleSwift[:] 所有火车票均已售完
-- ::49.086100+ StruggleSwift[:] 所有火车票均已售完
总结:可以看到在线程不安全的情况下,得到票数是错乱的,这样显然不符合我们的需求,所以我们需要考虑线程安全问题。
NSThread 线程安全
线程安全解决方案:可以给线程加锁,在一个线程执行该操作的时候,不允许其他线程进行操作。iOS 实现线程加锁有很多种方式。@synchronized、 NSLock、NSRecursiveLock、NSCondition、NSConditionLock、pthread_mutex、dispatch_semaphore、OSSpinLock、atomic(property) set/ge等等各种方式。为了简单起见,这里不对各种锁的解决方案和性能做分析,只用最简单的@synchronized来保证线程安全,从而解决线程同步问题。
//初始化火车票数量、卖票窗口(线程安全)、并开始卖票
- (void)initTicketStatusSave {
// 1. 设置剩余火车票为 50
self.ticketSurplusCount = ; // 2. 设置北京火车票售卖窗口的线程
self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
self.ticketSaleWindow1.name = @"北京火车票售票窗口"; // 3. 设置上海火车票售卖窗口的线程
self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
self.ticketSaleWindow2.name = @"上海火车票售票窗口"; // 4. 开始售卖火车票
[self.ticketSaleWindow1 start];
[self.ticketSaleWindow2 start]; } /**
* 售卖火车票(线程安全)
*/
- (void)saleTicketSafe {
while () {
// 互斥锁
@synchronized (self) {
//如果还有票,继续售卖
if (self.ticketSurplusCount > ) {
self.ticketSurplusCount --;
NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
[NSThread sleepForTimeInterval:0.2];
}
//如果已卖完,关闭售票窗口
else {
NSLog(@"所有火车票均已售完");
break;
}
}
}
}
打印结果:
-- ::20.960196+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::22.523697+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
<-------------------------NSThread线程结束-------------------------->
-- ::27.273431+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::27.273459+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::34.442708+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::34.442731+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::34.442731+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::34.647692+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::34.647657+ StruggleSwift[:] 剩余票数: 窗口:北京火车票售票窗口
-- ::36.308703+ StruggleSwift[:] 剩余票数: 窗口:上海火车票售票窗口
-- ::36.512623+ StruggleSwift[:] 所有火车票均已售完
-- ::36.512589+ StruggleSwift[:] 所有火车票均已售完
-- ::36.512572+ StruggleSwift[:] 所有火车票均已售完
-- ::37.557290+ StruggleSwift[:] 所有火车票均已售完
结论:在考虑了线程安全的情况下,加锁之后,得到的票数是正确的,没有出现混乱的情况。
线程的状态转换
SThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];,在内存中的表现为:

当调用[thread start];后,系统把线程对象放入可调度线程池中,线程对象进入就绪状态,如下图所示。

当然,可调度线程池中,会有其他的线程对象,如下图所示。在这里我们只关心左边的线程对象。

当前线程的状态转换
a. 如果CPU现在调度当前线程对象,则当前线程对象进入运行状态,如果CPU调度其他线程对象,则当前线程对象回到就绪状态。
b. 如果CPU在运行当前线程对象的时候调用了sleep方法\等待同步锁,则当前线程对象就进入了阻塞状态,等到sleep到时\得到同步锁,则回到就绪状态。
c. 如果CPU在运行当前线程对象的时候线程任务执行完毕\异常强制退出,则当前线程对象进入死亡状态。
只看文字可能不太好理解,具体当前线程对象的状态变化如下图所示。

NSThread(II)的更多相关文章
- ios 多线程之NSThread篇举例详解
这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇.总篇也包含了此文的链接.本文讲解的知识点有NSThread的开始.取消.在当前线程执行任务. ...
- Leetcode 笔记 113 - Path Sum II
题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...
- Leetcode 笔记 117 - Populating Next Right Pointers in Each Node II
题目链接:Populating Next Right Pointers in Each Node II | LeetCode OJ Follow up for problem "Popula ...
- 函数式Android编程(II):Kotlin语言的集合操作
原文标题:Functional Android (II): Collection operations in Kotlin 原文链接:http://antonioleiva.com/collectio ...
- 4.1/4.2 多线程进阶篇<上>(Pthread & NSThread)
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 本文源码 Demo 详见 Githubhttps://github.com/shorfng ...
- 统计分析中Type I Error与Type II Error的区别
统计分析中Type I Error与Type II Error的区别 在统计分析中,经常提到Type I Error和Type II Error.他们的基本概念是什么?有什么区别? 下面的表格显示 b ...
- hdu1032 Train Problem II (卡特兰数)
题意: 给你一个数n,表示有n辆火车,编号从1到n,入站,问你有多少种出站的可能. (题于文末) 知识点: ps:百度百科的卡特兰数讲的不错,注意看其参考的博客. 卡特兰数(Catalan):前 ...
- [LeetCode] Guess Number Higher or Lower II 猜数字大小之二
We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to gues ...
- [LeetCode] Number of Islands II 岛屿的数量之二
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
随机推荐
- 如何实现一个字符的反转 (Java)
一..通过jdk自带reverse的方法.
- flex布局 响应式布局
移动端页面开发流程 移动端页面布局 一.移动端app分类 1.Native App原生app手机应用程序 使用原生的语言开发的手机应用,Android系统用的是java,ios系统用的是objec ...
- 八、自定义starter
starter: 1.这个场景需要使用到的依赖是什么? 2.如何编写自动配置 @Configuration //指定这个类是一个配置类 @ConditionalOnXXX //在指定条件成立的情况下自 ...
- (1.6)MySQL执行计划
关键词:mysql执行计划 1.用法 [1.1]explain select * from tab_name........ [1.2]desc select * from tab_name..... ...
- redis缓存和mysql数据库同步
附redis关于缓存雪崩和缓存穿透,热点key 穿透 穿透:频繁查询一个不存在的数据,由于缓存不命中,每次都要查询持久层.从而失去缓存的意义. 解决办法: 持久层查询不到就缓存空结果,查询时先判断缓存 ...
- CentOS 下安装 Node.js 8.11.3 LTS Version
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google Chrome V8 JavaScript引擎,简单说是运行在服务端的 JavaScript.下面我们来演示一下Cen ...
- 微信公众号ID也可以修改了!
差不多一年前,微信团队宣布个人类帐号一个自然年内可主动修改两次名称,那一天大家奔走相告纷纷修改成自己早就心仪的名字,有人猛然发现公众号名字改了,可ID还是xiaopipi(小屁屁)这可如何是好,洗不去 ...
- Python3学习之路~5.7 Json & pickle 模块
用于序列化的两个模块 json,用于字符串 和 python数据类型间进行转换 pickle,用于python特有的类型 和 python的数据类型间进行转换 Json模块提供了四个功能:dumps. ...
- python的_thread模块来实现多线程(<python核心编程例子>)
python中_thread模块是一个低级别的多线程模块,它的问题在于主线程运行完毕后,会立马把子线程给结束掉,不加处理地使用_thread模块是不合适的.这里把书中讲述的有关_thread使用的例子 ...
- dll相关总结
1.动态链接库的使用有两种方式,一种是显式调用.一种是隐式调用. (1) 显式调用:使用LoadLibrary载入动态链接库.使用GetProcAddress获取某函数地址. (2) 隐式调用:可以使 ...