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虚拟机》三、Java虚拟机执行的数据入口(类文件结构)
1.Java如何实现平台无关系 Java要实现平台无关系就需要在Java代码和本地机器之间引入一个中间层,实现Java代码和本地机器的解耦,而这个中间层就是字节码.字节码独立于本地机器,以实现代码的可 ...
- pycharm换行
Pycharm自动换行 只对当前文件有效的操作是菜单栏->View -> Active Editor -> Use Soft Wraps. 要是想对所有文件都起到效果,就要在sett ...
- 升级my.cnf注意
升级my.cnf注意 mkdir -p /ngbs/data/{logs,tmp} vi /etc/init.d/mysqlbasedir=/usr/local/mysql datadir=/ngb ...
- IE8.0如何关闭启用内存保护帮助减少联机攻击?
默认情况下,该选项卡是灰色的(表示用户不能直接修改),win7电脑可以通过“以管理员身份”运行 IE 来放开该功能,但个别电脑即便用这种方法仍无法解决,此时,您可以试试如下方法: 1.在“运行”框中输 ...
- 20165236 2017-2018-2 《Java程序设计》结对编程练习_四则运算
20165236 2017-2018-2 <Java程序设计>结对编程练习_四则运算 结对小组:叶佺.郭金涛 一.需求分析: 1.能随机生成n道四则运算题目,n由使用者输入: 2.支持多种 ...
- 前端框架之Vue(6)-列表渲染
用v-for把一个数组对应为一组元素 我们用 v-for 指令根据一组数组的选项列表进行渲染. v-for 指令需要使用 item in items 形式的特殊语法, items 是源数据数组并且 i ...
- python的__new__方法
https://www.cnblogs.com/kex1n/p/5991249.html https://blog.csdn.net/wwx890208/article/details/8053445 ...
- 万恶之源 - Python 自定义模块
自定义模块 我们今天来学习一下自定义模块(也就是私人订制),我们要自定义模块,首先就要知道什么是模块啊 一个函数封装一个功能,比如现在有一个软件,不可能将所有程序都写入一个文件,所以咱们应该分文件,组 ...
- Windows下解压分卷压缩方法
各种压缩分卷格式 rar分卷格式是*.part1.rar,*.part2.rar 等等. 360分卷压缩出来的文件的名字是*.zip.001.*.zip002 等等. WinZip分卷压缩出来的文件名 ...
- 【Java】-NO.16.EBook.4.Java.1.012-【疯狂Java讲义第3版 李刚】- JDBC
1.0.0 Summary Tittle:[Java]-NO.16.EBook.4.Java.1.012-[疯狂Java讲义第3版 李刚]- JDBC Style:EBook Series:Java ...