我在上一篇文章讲了线程的生命周期,这篇文章来讲讲线程加锁的注意事项与@synchronized关键字。

那什么时候需要加锁呢,就是当多条线程同时操作一个变量时,就需要加锁了。至于为什么要加锁,可以看看文顶顶的这篇文章:http://www.cnblogs.com/wendingding/p/3805841.html, 写的非常明白。读本篇文章之前建议读一下。

上代码

声明变量

@interface ViewController ()
@property (strong, nonatomic)NSThread *thread1;
@property (strong, nonatomic)NSThread *thread2;
@property (strong, nonatomic)NSThread *thread3;
@property (assign, nonatomic)int leftTickets;
@end

实现代码

- (void)viewDidLoad {
[super viewDidLoad]; self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(sellTickets) object:nil];
self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sellTickets) object:nil];
self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(sellTickets) object:nil];
self.thread1.name = @"thread1";
self.thread2.name = @"thread2";
self.thread3.name = @"thread3";
// 总票数
self.leftTickets = 10;
}
// 点击屏幕开启线程
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.thread1 start];
[self.thread2 start];
[self.thread3 start];
}
- (void)sellTickets {
while (1) {
@synchronized (self) {
if (self.leftTickets > 0) {
[NSThread sleepForTimeInterval:0.2];
int count = self.leftTickets;
self.leftTickets = count - 1;
NSLog(@"剩余的票数%d",self.leftTickets);
NSLog(@"当前线程=%@", [NSThread currentThread]);
}else {
NSLog(@"票卖完了");
NSLog(@"退出线程%@",[NSThread currentThread]);
[NSThread exit];
}
}
}
}

打印日志

2016-11-04 11:52:25.117 TTTTTTTTTT[6753:74162] 剩余的票数9
2016-11-04 11:52:25.117 TTTTTTTTTT[6753:74162] 当前线程=<NSThread: 0x608000073880>{number = 3, name = thread1}
2016-11-04 11:52:25.393 TTTTTTTTTT[6753:74163] 剩余的票数8
2016-11-04 11:52:25.393 TTTTTTTTTT[6753:74163] 当前线程=<NSThread: 0x608000074540>{number = 4, name = thread2}
2016-11-04 11:52:25.661 TTTTTTTTTT[6753:74164] 剩余的票数7
2016-11-04 11:52:25.661 TTTTTTTTTT[6753:74164] 当前线程=<NSThread: 0x608000074580>{number = 5, name = thread3}
2016-11-04 11:52:25.932 TTTTTTTTTT[6753:74162] 剩余的票数6
2016-11-04 11:52:25.933 TTTTTTTTTT[6753:74162] 当前线程=<NSThread: 0x608000073880>{number = 3, name = thread1}
2016-11-04 11:52:26.164 TTTTTTTTTT[6753:74163] 剩余的票数5
2016-11-04 11:52:26.165 TTTTTTTTTT[6753:74163] 当前线程=<NSThread: 0x608000074540>{number = 4, name = thread2}
2016-11-04 11:52:26.438 TTTTTTTTTT[6753:74164] 剩余的票数4
2016-11-04 11:52:26.439 TTTTTTTTTT[6753:74164] 当前线程=<NSThread: 0x608000074580>{number = 5, name = thread3}
2016-11-04 11:52:26.704 TTTTTTTTTT[6753:74162] 剩余的票数3
2016-11-04 11:52:26.705 TTTTTTTTTT[6753:74162] 当前线程=<NSThread: 0x608000073880>{number = 3, name = thread1}
2016-11-04 11:52:26.975 TTTTTTTTTT[6753:74163] 剩余的票数2
2016-11-04 11:52:26.976 TTTTTTTTTT[6753:74163] 当前线程=<NSThread: 0x608000074540>{number = 4, name = thread2}
2016-11-04 11:52:27.232 TTTTTTTTTT[6753:74164] 剩余的票数1
2016-11-04 11:52:27.233 TTTTTTTTTT[6753:74164] 当前线程=<NSThread: 0x608000074580>{number = 5, name = thread3}
2016-11-04 11:52:27.505 TTTTTTTTTT[6753:74162] 剩余的票数0
2016-11-04 11:52:27.505 TTTTTTTTTT[6753:74162] 当前线程=<NSThread: 0x608000073880>{number = 3, name = thread1}
2016-11-04 11:52:27.505 TTTTTTTTTT[6753:74163] 票卖完了
2016-11-04 11:52:27.506 TTTTTTTTTT[6753:74163] 退出线程<NSThread: 0x608000074540>{number = 4, name = thread2}

我们一般用@synchronized来给线程加锁。它有什么用呢:

(1) 堵塞所在线程,线程里面剩下的任务只有当@synchronized里面的代码执行完毕才能继续往下执行,和队列的同步差不多是一个意思。

​(2)当执行@synchronized里面的代码之前,所在线程要先检查是否有其他的线程执行里面的代码。如果没有,才继续往下执行。

再看打印日志里面最后一条,说明了只有线程“thread3”退出了,其他的线程没有退出。

我上篇文章讲,不用管线程的退出,任务执行完线程会自动退出。但是这是一个while循环啊!如果不退出线程,线程会一直执行。

代码

- (void)sellTickets {
while (1) {
@synchronized (self) {
if (self.leftTickets > 0) {
[NSThread sleepForTimeInterval:0.2];
int count = self.leftTickets;
self.leftTickets = count - 1;
NSLog(@"剩余的票数%d",self.leftTickets);
NSLog(@"当前线程=%@", [NSThread currentThread]);
}else {
NSLog(@"票卖完了");
NSLog(@"退出线程%@",[NSThread currentThread]);
// 不让线程退出
//[NSThread exit];
}
}
}
}

打印的日志

2016-11-04 12:01:53.309 TTTTTTTTTT[7110:78974] 当前线程=<NSThread: 0x600000076f40>{number = 4, name = thread2}
2016-11-04 12:01:53.556 TTTTTTTTTT[7110:78973] 剩余的票数0
2016-11-04 12:01:53.556 TTTTTTTTTT[7110:78973] 当前线程=<NSThread: 0x600000076fc0>{number = 3, name = thread1}
2016-11-04 12:01:53.556 TTTTTTTTTT[7110:78975] 票卖完了
2016-11-04 12:01:53.557 TTTTTTTTTT[7110:78975] 退出线程<NSThread: 0x600000077240>{number = 5, name = thread3}
2016-11-04 12:01:53.558 TTTTTTTTTT[7110:78974] 票卖完了
2016-11-04 12:01:53.559 TTTTTTTTTT[7110:78974] 退出线程<NSThread: 0x600000076f40>{number = 4, name = thread2}
2016-11-04 12:01:53.560 TTTTTTTTTT[7110:78973] 票卖完了

那又为什么只有线程thread2退出呢?(注:每次退出的线程是不确定的)因为当线程thread2退出了,并没有执行完@synchronized里的方法,线程thread1和线程thread3还在等thread2执行完了,它们好去执行呢。但是线程thread2已经死了,不可能再执行了。这就造成线程thread1和线程thread3一直都在内存里,没有被退出,造成了CPU不必要的开销,所以我们最好不要在@synchronized里面退出线程。

- (void)sellTickets {
while (1) {
@synchronized (self) {
if (self.leftTickets > 0) {
[NSThread sleepForTimeInterval:0.2];
int count = self.leftTickets;
self.leftTickets = count - 1;
NSLog(@"剩余的票数%d",self.leftTickets);
NSLog(@"当前线程=%@", [NSThread currentThread]);
}
}
if (self.leftTickets == 0) {
NSLog(@"票卖完了");
NSLog(@"退出线程%@",[NSThread currentThread]);
[NSThread exit];
}
}
}
2016-11-04 12:06:51.795 TTTTTTTTTT[7295:81206] 票卖完了
2016-11-04 12:06:51.795 TTTTTTTTTT[7295:81207] 票卖完了
2016-11-04 12:06:51.795 TTTTTTTTTT[7295:81208] 票卖完了
2016-11-04 12:06:51.796 TTTTTTTTTT[7295:81206] 退出线程<NSThread: 0x60000026a3c0>{number = 3, name = thread1}
2016-11-04 12:06:51.796 TTTTTTTTTT[7295:81207] 退出线程<NSThread: 0x60000026a380>{number = 4, name = thread2}
2016-11-04 12:06:51.796 TTTTTTTTTT[7295:81208] 退出线程<NSThread: 0x60000026a740>{number = 5, name = thread3}

这就是NSThread加锁以及加锁的一些注意事项。如果感觉对你有用,记得关注啊,我会每周分享一些技术心得。

iOS多线程之2.NSThread的加锁@synchronized的更多相关文章

  1. iOS多线程之3.NSThread的线程间通信

      我们把一些耗时操作放在子线程,例如下载图片,但是下载完毕我们不能在子线程更新UI,因为只有主线程才可以更新UI和处理用户的触摸事件,否则程序会崩溃.此时,我们就需要把子线程下载完毕的数据传递到主线 ...

  2. iOS多线程之8.NSOPeration的其他用法

      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...

  3. iOS多线程之GCD小记

    iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...

  4. 多线程之pthread, NSThread, NSOperation, GCD

    关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD p ...

  5. iOS多线程之Thread

    多线程 • Thread 是苹果官方提供的,简单已用,可以直接操作线程对象.不过需要程序员自己管理线程的生命周期,主要是创建那部分 优缺点 面向对象,简单易用 直接操作线程对象 需要自己管理线程生命周 ...

  6. iOS多线程之GCD学习笔记

    什么是GCD 1.全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 2.纯C语言,提供了非常多强大的函数 GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 G ...

  7. iOS多线程之NSThread使用

    iOS中的多线程技术 我们在iOS开发项目过程中,为了解决UI界面操作不被耗时操作阻塞,我们会使用到多线程技术.在iOS开发中,我们主要会用到三种多线程操作技术:NSThread,NSOperatio ...

  8. 【原】iOS多线程之NSThread、NSOperationQueue、NSObject和GCD的区别

    区别: Thread: 是这几种方式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步.线程共享同一应用程序的部分内存空间, 它们拥有对数据相同的访问权限. ...

  9. ios 多线程之NSThread篇举例详解

    这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇.总篇也包含了此文的链接.本文讲解的知识点有NSThread的开始.取消.在当前线程执行任务. ...

随机推荐

  1. C#由变量捕获引起对闭包的思考

    前言 偶尔翻翻书籍看看原理性的东西确实有点枯燥,之前有看到园中有位园友说到3-6年工作经验的人应该了解的.NET知识,其中就有一点是关于C#中的闭包,其实早之前在看书时(之前根本不知道C#中还有闭包这 ...

  2. C# 复制一个Word文档的部分或全部内容到另一个Word文档

    C# 复制一个Word文档的部分或全部内容到另一个Word文档 我最近喜欢折腾Office软件相关的东西,想把很多Office软件提供的功能用.NET来实现,如果后期能把它用来开发一点我自己的小应用程 ...

  3. 如何在ios中集成微信登录功能

    在ios中集成微信的登录功能有两种方法 1 用微信原生的api来做,这样做的好处就是轻量级,程序负重小,在Build Settings 中这样设置 然后设置 友盟的设置同上,但是要注意,加入你需要的所 ...

  4. C语言 基础练习40题

    一.题目 1.输入2个整数,求两数的平方和并输出. 2. 输入一个圆半径(r)当r>=0时,计算并输出圆的面积和周长,否则,输出提示信息. 3.函数y=f(x)可表示为: 4.编写一个程序,从4 ...

  5. 1Z0-053 争议题目解析46

    1Z0-053 争议题目解析46 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 46.What happens when you run the SQL Tuning Adviso ...

  6. 关于Java中的transient关键字

    Java中的transient关键字是在序列化时候用的,如果用transient修饰变量,那么该变量不会被序列化. 下面的例子中创建了一个Student类,有三个成员变量:id,name,age.ag ...

  7. 图片每天换及纯css3手风琴特效

    <a target="_blank" id="a"><img id="img" /></a> <s ...

  8. 使用Apache Server 的ab进行web请求压力测试

    参考:http://www.cnblogs.com/spring3mvc/archive/2010/11/23/2414741.html 自己写代码经常是顺着逻辑写下去,写完后run一下,ok就玩完事 ...

  9. Windows Phone 8 开发系列(持续更新中)

    1. 从应用列表再次点击应用,如何恢复到上次浏览的页面呢? 2. Windows Phone 文本框的 UpdateSourceTrigger 属性不支持 PropertyChanged 怎么办? 3 ...

  10. 浅析String不可变性

    在所有编程语言领域,我想字符串应该是地球上最常用的表达手段了吧. 在java的世界里,String是作为类出现的,核心的一个域就是一个char数组,内部就是通过维护一个不可变的char数组,来向外部输 ...