多线程(三) iOS中的锁
锁的类别:互斥锁,递归锁,条件锁,自旋锁等
锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等
下面说一下常用的几种锁:
1.@synchronized:对象级别所,互斥锁,性能较差不推荐使用
@synchronized(这里添加一个OC对象,一般使用self) {
这里写要加锁的代码
}
@synchronized使用注意点
1.加锁的代码尽量少
2.添加的OC对象必须在多个线程中都是同一对象,下面举一个反例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
- ( void )viewDidLoad { [ super viewDidLoad]; //设置票的数量为5 _tickets = 5; //线程一 NSThread *threadOne = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; threadOne.name = @ "threadOne" ; //线程二 NSThread *threadTwo = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; //开启线程 [threadOne start]; [threadTwo start]; } - ( void )saleTickets { NSObject *object = [[ NSObject alloc] init]; while (1) { @synchronized (object) { [ NSThread sleepForTimeInterval:1]; if (_tickets > 0) { _tickets--; NSLog (@ "剩余票数= %ld" ,_tickets); } else { NSLog (@ "票卖完了" ); break ; } } } } |
结果卖票又出错了,出现这个原因的问题是每个线程都会创建一个object对象,锁后面加的object在不同线程中就不同了;
把@synchronized(object)改成 @synchronized(self)就能得到了正确结果
2.NSLock:互斥锁,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
@interface ViewController () { NSLock *mutexLock; } @property (assign, nonatomic ) NSInteger tickets; @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; //创建锁 mutexLock = [[ NSLock alloc] init]; //设置票的数量为5 _tickets = 5; //线程一 NSThread *threadOne = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; threadOne.name = @ "threadOne" ; //线程二 NSThread *threadTwo = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; //开启线程 [threadOne start]; [threadTwo start]; } - ( void )saleTickets { while (1) { [ NSThread sleepForTimeInterval:1]; //加锁 [mutexLock lock]; if (_tickets > 0) { _tickets--; NSLog (@ "剩余票数= %ld" ,_tickets); } else { NSLog (@ "票卖完了" ); break ; } //解锁 [mutexLock unlock]; } } |
NSLock: 使用注意,不能多次调用 lock方法,会造成死锁
3.NSRecursiveLock:递归锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
@interface ViewController () { NSRecursiveLock *rsLock; } @property (assign, nonatomic ) NSInteger tickets; @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; //创建锁递归锁 rsLock = [[ NSRecursiveLock alloc] init]; //设置票的数量为5 _tickets = 5; //线程一 NSThread *threadOne = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; threadOne.name = @ "threadOne" ; //线程二 NSThread *threadTwo = [[ NSThread alloc] initWithTarget: self selector: @selector (saleTickets) object: nil ]; //开启线程 [threadOne start]; [threadTwo start]; } - ( void )saleTickets { while (1) { [ NSThread sleepForTimeInterval:1]; //加锁,递归锁可以多次加锁 [rsLock lock]; [rsLock lock]; if (_tickets > 0) { _tickets--; NSLog (@ "剩余票数= %ld" ,_tickets); } else { NSLog (@ "票卖完了" ); break ; } //解锁,只有对应次数解锁,其他线程才能访问。 [rsLock unlock]; [rsLock unlock]; } } |
4.NSConditionLock:条件锁
NSConditionLock:条件锁,一个线程获得了锁,其它线程等待。
[xxxx lock]; 表示 xxx 期待获得锁,如果没有其他线程获得锁(不需要判断内部的condition) 那它能执行此行以下代码,如果已经有其他线程获得锁(可能是条件锁,或者无条件锁),则等待,直至其他线程解锁
[xxx lockWhenCondition:A条件]; 表示如果没有其他线程获得该锁,但是该锁内部的condition不等于A条件,它依然不能获得锁,仍然等待。如果内部的condition等于A条件,并且没有其他线程获得该锁,则进入代码区,同时设置它获得该锁,其他任何线程都将等待它代码的完成,直至它解锁。
[xxx unlockWithCondition:A条件]; 表示释放锁,同时把内部的condition设置为A条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
@interface ViewController () { NSConditionLock *_cdtLock; //条件锁 } @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; //创建条件锁 _cdtLock = [[ NSConditionLock alloc] init]; [ NSThread detachNewThreadSelector: @selector (conditionLockAction1) toTarget: self withObject: nil ]; [ NSThread detachNewThreadSelector: @selector (conditionLockAction2) toTarget: self withObject: nil ]; } - ( void )conditionLockAction1 { //阻塞线程2s [ NSThread sleepForTimeInterval:2]; for ( NSInteger i = 0; i < 3; i++) { //加锁 [_cdtLock lock]; NSLog (@ "i = %li" , i); //释放锁,并设置condition属性的值为i [_cdtLock unlockWithCondition:i]; } } - ( void )conditionLockAction2 { //当标识为2时同步代码段才能够执行,如果标识为其它数字则当前线程被阻塞。 [_cdtLock lockWhenCondition:2]; NSLog (@ "thread2" ); [_cdtLock unlock]; } |
打印结果:
如果我们把代码中[_cdtLock lockWhenCondition:2]换成[_cdtLock lockWhenCondition:1]则会发现出现如下结果
和我们预想的在i = 1后面打印thread2不符合,这是因为conditionLockAction1中的代码段也需要获得锁,同时在循环执行过后把condition置成了2,那么conditionLockAction2就再也没机会加锁了,所以不打印thread2。
我们可以靠下面的代码验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
@interface ViewController () { NSConditionLock *_cdtLock; //条件锁 } @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; //创建条件锁 _cdtLock = [[ NSConditionLock alloc] init]; [ NSThread detachNewThreadSelector: @selector (conditionLockAction1) toTarget: self withObject: nil ]; [ NSThread detachNewThreadSelector: @selector (conditionLockAction2) toTarget: self withObject: nil ]; } - ( void )conditionLockAction1 { //阻塞线程2s [ NSThread sleepForTimeInterval:2]; for ( NSInteger i = 0; i < 3; i++) { //加锁 [_cdtLock lock]; NSLog (@ "i = %li" , i); //释放锁,并设置condition属性的值为i [_cdtLock unlockWithCondition:i]; <span style= "color: #ff0000;" > //在i 为 1的时候阻塞线程1s if (i == 1) { [ NSThread sleepForTimeInterval:1]; }</span> } } - ( void )conditionLockAction2 { //当标识为2时同步代码段才能够执行,如果标识为其它数字则当前线程被阻塞。 [_cdtLock lockWhenCondition:1]; NSLog (@ "thread2" ); [_cdtLock unlock]; } |
现在的结果就和我们预期的一样了
5.NSCondition:可以理解为互斥锁和条件锁的结合
用生产者消费者中的例子可以很好的理解NSCondition
1.生产者要取得锁,然后去生产,生产后将生产的商品放入库房,如果库房满了,则wait,就释放锁,直到其它线程唤醒它去生产,如果没有满,则生产商品后调用signal,可以唤醒在此condition上等待的线程。
2.消费者要取得锁,然后去消费,如果当前没有商品,则wait,释放锁,直到有线程去唤醒它消费,如果有商品,则消费后会通知正在等待的生产者去生产商品。
生产者和消费者的关键是:当库房已满时,生产者等待,不再继续生产商品,当库房已空时,消费者等待,不再继续消费商品,走到库房有商品时,会由生产者通知消费来消费。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
- ( void )conditionTest { //创建数组存放商品 products = [[ NSMutableArray alloc] init]; condition = [[ NSCondition alloc] init]; [ NSThread detachNewThreadSelector: @selector (createProducter) toTarget: self withObject: nil ]; [ NSThread detachNewThreadSelector: @selector (createConsumenr) toTarget: self withObject: nil ]; } - ( void )createConsumenr { while (1) { //模拟消费商品时间,让它比生产慢一点 [ NSThread sleepForTimeInterval:arc4random()%10 * 0.1 + 1.5]; [condition lock]; while (products.count == 0) { NSLog (@ "商品为0,等待生产" ); [condition wait]; } [products removeLastObject]; NSLog (@ "消费了一个商品,商品数 = %ld" ,products.count); [condition signal]; [condition unlock]; } } - ( void )createProducter { while (1) { //模拟生产商品时间 [ NSThread sleepForTimeInterval:arc4random()%10 * 0.1 + 0.5]; [condition lock]; while (products.count == 5) { NSLog (@ "商品满了,等待消费" ); [condition wait]; } [products addObject:[[ NSObject alloc] init]]; NSLog (@ "生产了一个商品,商品数%ld" ,products.count); [condition signal]; [condition unlock]; } } |
了解死锁
概念:死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
产生死锁的4个必要条件
多线程(三) iOS中的锁的更多相关文章
- 谈谈iOS中的锁
1 前言 近日工作不是太忙,刚好有时间了解一些其他东西,本来打算今天上午去体检,但是看看天气还是明天再去吧,也有很大一个原因:就是周六没有预约上!闲话少说,这里简单对锁来个简单介绍分享. 2 目录 第 ...
- 多线程(三) java中线程的简单使用
java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...
- JAVA多线程(三) 线程池和锁的深度化
github演示代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-servic ...
- 多线程 (三)iOS中的锁
锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...
- java多线程并发编程中的锁
synchronized: https://www.cnblogs.com/dolphin0520/p/3923737.html Lock:https://www.cnblogs.com/dolphi ...
- 深入理解 iOS 开发中的锁
来源:伯乐在线 - 夏天然后 链接:http://ios.jobbole.com/89474/ 点击 → 申请加入伯乐在线专栏作者 摘要 本文的目的不是介绍 iOS 中各种锁如何使用,一方面笔者没有大 ...
- Java并发编程(3) JUC中的锁
一 前言 前面已经说到JUC中的锁主要是基于AQS实现,而AQS(AQS的内部结构 .AQS的设计与实现)在前面已经简单介绍过了.今天记录下JUC包下的锁是怎么基于AQS上实现的 二 同步锁 同步锁不 ...
- iOS中的几种锁的总结,三种开启多线程的方式(GCD、NSOperation、NSThread)
学习内容 欢迎关注我的iOS学习总结--每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary OC中的几种锁 为什么要引入锁 ...
- 多线程在iOS开发中的应用
多线程基本概念 01 进程 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 02 线程 2-1 基本概念 1个进程要想执行任务,必须得有线程 ...
随机推荐
- RHEL CentOS Fedora各种源介绍和安装
CentOS默认自带CentOS-Base.repo源,但官方源中去除了很多有版权争议的软件,而且安装的软件也不是最新的稳定版. 下面介绍各种第三方软件库,以下软件库适用于与RHEL完全兼容的li ...
- DIV相对于父DIV底部对齐的实现方法
代码如下 <style type="text/css"> .box1 {border:1px #cccccc solid; width:500px; height:60 ...
- redis参数配置
redis.conf配置文件 配置项 值 说明 slave-read-only yes slave是否只读 slave-serve-stale-data yes 当slave与master断开连接,s ...
- 【重点突破】——第三方绘图工具FusionCharts.js的使用详解
一.引言 项目组中,经常会因为绘制图表的繁杂度,衡量会不会使用第三方绘图工具,如果自己做很困难,成本使用高于第三方绘图工具库,就会使用.很多人使用的是Chart.js,因为它是免费使用的,不过,缺点就 ...
- hdu2222Keywords Search字典树入门……
#include<iostream> #include<cstring> using namespace std; struct node { int num; node *n ...
- hdfs笔记
Distributed File System 数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文 ...
- OpenTSDB设计解读
OpenTSDB是基于HBase存储时间序列数据的一个开源数据库,确切地说,它仅仅是一个HBase的应用而已,其对于时间序列数据的处理能够供其它系统參考和借鉴.本文会针对它在数据库的设计方面展开一些探 ...
- 我如何添加一个空目录到Git仓库?
新建了一个仓库,只是创建一些目录结构,还不里面放什么,要放的内容还没有,还不存在,应该怎么办呢? Git 是不跟踪空目录的,所以需要跟踪那么就需要添加文件! 也就是说 Git 中不存在真正意义上的空目 ...
- android开发笔记之fastboot的使用
fastboot命令大全 在终端中.我们输入: fastboot 对于这些命令.我不解释,慢慢使用.慢慢的就会明确是怎么回事了. android分区 分区 作用 splash1 开机画面.使用Nand ...
- S:33184777
https://github.com/wjlWork/Crawl/tree/da0b63bc43bd7c238963f834a11df2581cecfb9c https://github.com/wh ...