多线程(三) 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 {    [superviewDidLoad];    //设置票的数量为5    _tickets = 5;    //线程一    NSThread*threadOne = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];    threadOne.name = @"threadOne";    //线程二    NSThread*threadTwo = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];        //开启线程    [threadOne start];    [threadTwo start];}- (void)saleTickets{    NSObject*object = [[NSObjectalloc] init];    while(1)    {        @synchronized(object) {            [NSThreadsleepForTimeInterval: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 | @interfaceViewController (){    NSLock*mutexLock;}@property(assign, nonatomic)NSIntegertickets;@end@implementationViewController- (void)viewDidLoad {    [superviewDidLoad];    //创建锁    mutexLock = [[NSLockalloc] init];        //设置票的数量为5    _tickets = 5;    //线程一    NSThread*threadOne = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];    threadOne.name = @"threadOne";    //线程二    NSThread*threadTwo = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];        //开启线程    [threadOne start];    [threadTwo start]; }- (void)saleTickets{    while(1)    {        [NSThreadsleepForTimeInterval: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 | @interfaceViewController (){    NSRecursiveLock*rsLock;}@property(assign, nonatomic)NSIntegertickets;@end@implementationViewController- (void)viewDidLoad {    [superviewDidLoad];    //创建锁递归锁    rsLock = [[NSRecursiveLockalloc] init];       //设置票的数量为5    _tickets = 5;    //线程一    NSThread*threadOne = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];    threadOne.name = @"threadOne";    //线程二    NSThread*threadTwo = [[NSThreadalloc] initWithTarget:selfselector:@selector(saleTickets) object:nil];    //开启线程    [threadOne start];    [threadTwo start];   }- (void)saleTickets{    while(1)    {        [NSThreadsleepForTimeInterval: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 | @interfaceViewController () {       NSConditionLock*_cdtLock; //条件锁}@end@implementationViewController- (void)viewDidLoad {    [superviewDidLoad];        //创建条件锁    _cdtLock = [[NSConditionLockalloc] init];    [NSThreaddetachNewThreadSelector:@selector(conditionLockAction1) toTarget:selfwithObject:nil];    [NSThreaddetachNewThreadSelector:@selector(conditionLockAction2) toTarget:selfwithObject:nil];    }- (void)conditionLockAction1 {        //阻塞线程2s    [NSThreadsleepForTimeInterval:2];        for(NSIntegeri = 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。
和我们预想的在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 | @interfaceViewController () {       NSConditionLock*_cdtLock; //条件锁}@end@implementationViewController- (void)viewDidLoad {    [superviewDidLoad];        //创建条件锁    _cdtLock = [[NSConditionLockalloc] init];    [NSThreaddetachNewThreadSelector:@selector(conditionLockAction1) toTarget:selfwithObject:nil];    [NSThreaddetachNewThreadSelector:@selector(conditionLockAction2) toTarget:selfwithObject:nil];    }- (void)conditionLockAction1 {        //阻塞线程2s    [NSThreadsleepForTimeInterval:2];        for(NSIntegeri = 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)        {            [NSThreadsleepForTimeInterval: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 = [[NSMutableArrayalloc] init];    condition = [[NSConditionalloc] init];        [NSThreaddetachNewThreadSelector:@selector(createProducter) toTarget:selfwithObject:nil];    [NSThreaddetachNewThreadSelector:@selector(createConsumenr) toTarget:selfwithObject:nil];}- (void)createConsumenr{    while(1) {        //模拟消费商品时间,让它比生产慢一点        [NSThreadsleepForTimeInterval: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) {        //模拟生产商品时间        [NSThreadsleepForTimeInterval:arc4random()%10 * 0.1 + 0.5];        [condition lock];        while(products.count == 5)        {            NSLog(@"商品满了,等待消费");            [condition wait];        }        [products addObject:[[NSObjectalloc] 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个进程要想执行任务,必须得有线程 ... 
随机推荐
- dedecms 调用栏目或文章所属上下级关系
			效果如下: 代码如下: <div class="place"> <strong>当前位置:</strong> {dede:field name= ... 
- Cookie常用方法封装Utils
			1.查询某个指定的cookie package com.sun.etalk.cookie; import javax.servlet.http.Cookie; public class CookieU ... 
- node在Fedora 22系统下开发环境搭建
			事实上,环境搭建在linux系统还是比較简单的,下载已经编译好的包,配置一下环境变量. 或者下载源代码,自己编译. 这里记录一下,主要是node版本号变化节奏很块的情况下.怎样配置一次环境变量就不要再 ... 
- 使用Shiro
			一.架构 要学习如何使用Shiro必须先从它的架构谈起,作为一款安全框架Shiro的设计相当精妙.Shiro的应用不依赖任何容器,它也可以在JavaSE下使用.但是最常用的环境还是JavaEE.下面以 ... 
- 怎样使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(3)
			plist 中的每一页 utteranceSting 我们都创建了一个RWTPage.displayText.因此,每页的文本会一次性地显示出来. 由于 You've constructedeach ... 
- 重读金典------高质量C编程指南(林锐)-------第七章 内存管理
			2015/12/10补充: 当我们需要给一个数组返回所赋的值的时候,我们需要传入指针的指针.当我们只需要一个值的时候,传入指针即可,或者引用也可以. 结构大致如下: char* p = (char*) ... 
- iOS SDK具体解释之UIDevice(系统版本号,设备型号...)
			原创Blog,转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的iOS SDK具体解释专栏 blog.csdn.net/column/details/huangwenchen ... 
- C语言的空格问题
			对于C语言中,一般的理解是对于空格,我们可以随意输入,因为空格没啥大意义,但是事实上并非如此. 1.'\'空格的问题 '\' 字符可用于一些字符进行转移,当然也包括了 newline(enter),被 ... 
- mybatis数据查询返回值
			查询: 返回值是整数. 小于0是查询的数据不存在,大于0是查询的数据已经存在. 修改: 返回值是整数. 大于0是修改的数据成功,否则就是失败. 添加: 和修改同理. 
- 修改登陆织梦后台的“DedeCMS 提示信息”
			修改方法: 在dedecms程序的include目录中找到文件common.func.php并对其进行编辑,把其中的“DedeCMS 提示信息”修改为自己想要的内容提示: 在dedecms程序的默认管 ... 
