• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Harley
博客园    首页    新随笔    联系   管理    订阅  订阅

NSThread(II)

非线程安全

 1 //初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
 2 - (void)initTicketStatusNotSave {
 3     // 1. 设置剩余火车票为 50
 4     self.ticketSurplusCount = 10;
 5     
 6     // 2. 设置北京火车票售卖窗口的线程
 7     self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];
 8     self.ticketSaleWindow1.name = @"北京火车票售票窗口";
 9     
10     // 3. 设置上海火车票售卖窗口的线程
11     self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketNotSafe) object:nil];
12     self.ticketSaleWindow2.name = @"上海火车票售票窗口";
13     
14     // 4. 开始售卖火车票
15     [self.ticketSaleWindow1 start];
16     [self.ticketSaleWindow2 start];
17     
18 }
19 
20 /**
21  * 售卖火车票(非线程安全)
22  */
23 - (void)saleTicketNotSafe {
24     while (1) {
25         //如果还有票,继续售卖
26         if (self.ticketSurplusCount > 0) {
27             self.ticketSurplusCount --;
28             NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
29             [NSThread sleepForTimeInterval:0.2];
30         }
31         //如果已卖完,关闭售票窗口
32         else {
33             NSLog(@"所有火车票均已售完");
34             break;
35         }
36     }
37 }
View Code

 

打印结果:

 1 <-------------------------NSThread线程结束------------------------2018-04-04 13:44:34.640134+0800 StruggleSwift[3660:189882] 剩余票数:9 窗口:北京火车票售票窗口
 2 -->
 3 2018-04-04 13:44:37.602762+0800 StruggleSwift[3660:189887] 剩余票数:8 窗口:上海火车票售票窗口
 4 2018-04-04 13:44:39.144970+0800 StruggleSwift[3660:189882] 剩余票数:6 窗口:北京火车票售票窗口
 5 2018-04-04 13:44:39.144970+0800 StruggleSwift[3660:189887] 剩余票数:6 窗口:上海火车票售票窗口
 6 2018-04-04 13:44:40.939316+0800 StruggleSwift[3660:189882] 剩余票数:5 窗口:北京火车票售票窗口
 7 2018-04-04 13:44:40.939316+0800 StruggleSwift[3660:189887] 剩余票数:5 窗口:上海火车票售票窗口
 8 2018-04-04 13:44:42.343211+0800 StruggleSwift[3660:189887] 剩余票数:4 窗口:上海火车票售票窗口
 9 2018-04-04 13:44:42.343219+0800 StruggleSwift[3660:189882] 剩余票数:4 窗口:北京火车票售票窗口
10 2018-04-04 13:44:43.646726+0800 StruggleSwift[3660:189887] 剩余票数:3 窗口:上海火车票售票窗口
11 2018-04-04 13:44:43.646728+0800 StruggleSwift[3660:189882] 剩余票数:3 窗口:北京火车票售票窗口
12 2018-04-04 13:44:45.168354+0800 StruggleSwift[3660:189882] 剩余票数:2 窗口:北京火车票售票窗口
13 2018-04-04 13:44:45.168361+0800 StruggleSwift[3660:189887] 剩余票数:2 窗口:上海火车票售票窗口
14 2018-04-04 13:44:47.232723+0800 StruggleSwift[3660:189882] 剩余票数:0 窗口:北京火车票售票窗口
15 2018-04-04 13:44:47.232735+0800 StruggleSwift[3660:189887] 剩余票数:0 窗口:上海火车票售票窗口
16 2018-04-04 13:44:49.086100+0800 StruggleSwift[3660:189882] 所有火车票均已售完
17 2018-04-04 13:44:49.086100+0800 StruggleSwift[3660:189887] 所有火车票均已售完

总结:可以看到在线程不安全的情况下,得到票数是错乱的,这样显然不符合我们的需求,所以我们需要考虑线程安全问题。 

 

NSThread 线程安全

线程安全解决方案:可以给线程加锁,在一个线程执行该操作的时候,不允许其他线程进行操作。iOS 实现线程加锁有很多种方式。@synchronized、 NSLock、NSRecursiveLock、NSCondition、NSConditionLock、pthread_mutex、dispatch_semaphore、OSSpinLock、atomic(property) set/ge等等各种方式。为了简单起见,这里不对各种锁的解决方案和性能做分析,只用最简单的@synchronized来保证线程安全,从而解决线程同步问题。

 1 //初始化火车票数量、卖票窗口(线程安全)、并开始卖票
 2 - (void)initTicketStatusSave {
 3     // 1. 设置剩余火车票为 50
 4     self.ticketSurplusCount = 10;
 5     
 6     // 2. 设置北京火车票售卖窗口的线程
 7     self.ticketSaleWindow1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
 8     self.ticketSaleWindow1.name = @"北京火车票售票窗口";
 9     
10     // 3. 设置上海火车票售卖窗口的线程
11     self.ticketSaleWindow2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicketSafe) object:nil];
12     self.ticketSaleWindow2.name = @"上海火车票售票窗口";
13     
14     // 4. 开始售卖火车票
15     [self.ticketSaleWindow1 start];
16     [self.ticketSaleWindow2 start];
17     
18 }
19 
20 /**
21  * 售卖火车票(线程安全)
22  */
23 - (void)saleTicketSafe {
24     while (1) {
25         // 互斥锁
26         @synchronized (self) {
27             //如果还有票,继续售卖
28             if (self.ticketSurplusCount > 0) {
29                 self.ticketSurplusCount --;
30                 NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%ld 窗口:%@", self.ticketSurplusCount, [NSThread currentThread].name]);
31                 [NSThread sleepForTimeInterval:0.2];
32             }
33             //如果已卖完,关闭售票窗口
34             else {
35                 NSLog(@"所有火车票均已售完");
36                 break;
37             }
38         }
39     }
40 }
View Code

 

打印结果:

 1 2018-04-09 10:38:20.960196+0800 StruggleSwift[1190:23146] 剩余票数:9 窗口:北京火车票售票窗口
 2 2018-04-09 10:38:22.523697+0800 StruggleSwift[1190:23147] 剩余票数:8 窗口:上海火车票售票窗口
 3 <-------------------------NSThread线程结束-------------------------->
 4 2018-04-09 10:38:27.273431+0800 StruggleSwift[1190:23146] 剩余票数:7 窗口:北京火车票售票窗口
 5 2018-04-09 10:38:27.273459+0800 StruggleSwift[1190:23147] 剩余票数:6 窗口:上海火车票售票窗口
 6 2018-04-09 10:38:34.442708+0800 StruggleSwift[1190:23683] 剩余票数:5 窗口:北京火车票售票窗口
 7 2018-04-09 10:38:34.442731+0800 StruggleSwift[1190:23146] 剩余票数:4 窗口:北京火车票售票窗口
 8 2018-04-09 10:38:34.442731+0800 StruggleSwift[1190:23147] 剩余票数:3 窗口:上海火车票售票窗口
 9 2018-04-09 10:38:34.647692+0800 StruggleSwift[1190:23147] 剩余票数:2 窗口:上海火车票售票窗口
10 2018-04-09 10:38:34.647657+0800 StruggleSwift[1190:23146] 剩余票数:1 窗口:北京火车票售票窗口
11 2018-04-09 10:38:36.308703+0800 StruggleSwift[1190:23694] 剩余票数:0 窗口:上海火车票售票窗口
12 2018-04-09 10:38:36.512623+0800 StruggleSwift[1190:23683] 所有火车票均已售完
13 2018-04-09 10:38:36.512589+0800 StruggleSwift[1190:23146] 所有火车票均已售完
14 2018-04-09 10:38:36.512572+0800 StruggleSwift[1190:23147] 所有火车票均已售完
15 2018-04-09 10:38:37.557290+0800 StruggleSwift[1190:23694] 所有火车票均已售完

结论:在考虑了线程安全的情况下,加锁之后,得到的票数是正确的,没有出现混乱的情况。

 

线程的状态转换

SThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];,在内存中的表现为: 

 

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

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

当前线程的状态转换

  a. 如果CPU现在调度当前线程对象,则当前线程对象进入运行状态,如果CPU调度其他线程对象,则当前线程对象回到就绪状态。

  b. 如果CPU在运行当前线程对象的时候调用了sleep方法\等待同步锁,则当前线程对象就进入了阻塞状态,等到sleep到时\得到同步锁,则回到就绪状态。

  c. 如果CPU在运行当前线程对象的时候线程任务执行完毕\异常强制退出,则当前线程对象进入死亡状态。

只看文字可能不太好理解,具体当前线程对象的状态变化如下图所示。

 

posted @ 2018-04-04 13:50  Harely  阅读(182)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3