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 ...
随机推荐
- Struts2漏洞检查工具
- tensorflow入门笔记(五) name_scope和variable_scope
一.上下文管理器(context manager) 上下文管理器是实现了上下文协议的对象,主要用于资源的获取与释放.上下文协议包括__enter__.__exit__,简单说就是,具备__enter_ ...
- nodejs 学习二, nodejs调试
nodejs 调试,在官方文档(英文),常用的两种: 一个在chrome安装插件inspector 第二种利用编辑 这里我使用vscode编辑来调试. 主要是配置 launch.json(用vscod ...
- java定时任务的三种方式
/** * 普通thread * 这是最常见的,创建一个thread,然后让它在while循环里一直运行着, * 通过sleep方法来达到定时任务的效果.这样可以快速简单的实现,代码如下 */ ...
- LigerUi遮罩的两个方法
$.ligerDialog.waitting('正在查询,请稍候...'); $.ligerDialog.close();
- springmvc aop 事务配置
对应的中文: 任意公共方法的执行: execution(public * *(..)) 任何一个以“set”开始的方法的执行: execution(* set*(..)) AccountService ...
- [py]初始化dict结构和json.dump使用
1.json.dump使用 http://python3-cookbook.readthedocs.io/zh_CN/latest/c06/p02_read-write_json_data.html ...
- 继承时,当父子类都具有相同的成员变量,默认情况下是直接调用子类的成员变量,当要调用父类的成员变量则需要使用super关键之
package day02; public class Person { String name="fl"; }class Car{ }class Student extends ...
- xcodebuild 打包
我的xcode版本比较高,查找的一些低版本的构建都不可用,所以在此记录我的打包过程. 1.app代码仓需要发布的ipa的打包:采用achieve的方式 (1)前期工作 mkdir arch archi ...
- [Java in NetBeans] Lesson 05. Method/function
这个课程的参考视频和图片来自youtube. 主要学到的知识点有: Define a method:(motivation: write one time, but use it many times ...