iOS多线程同步之NSLock实战例子

IOS多线程同步问题 IOS开发多线程开发,同步块,NSLock,NSCondition 阅读详情

场景:用户账户初始有1000元钱,开10个线程同时进行存钱和取钱操作,10个线程同时执行,其中5个线程负责存钱操作,5个线程负责取钱操作。
(1) 5个存钱线程,每个线程每隔0.1毫秒存入100元,执行10W次;
(1) 5个取钱线程,每个线程每隔0.1毫秒取出100元,执行10W次;
可以预期的结果是:存钱线程和取钱线程存入和取出刚好相互抵消,当所有线程执行完的时候,用户账号余额仍然是1000元。
上代码,账户类Accounter.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
/**
 账户类
 */
@interface Accounter : NSObject

@property (nonatomic, assign) int balance;  // 余额

@end

NS_ASSUME_NONNULL_END

账户类Accounter.m

#import "Accounter.h"

@implementation Accounter

@end

ViewController.m
ViewController.m开5个线程存钱,5个线程取钱。当线程全部执行完毕的时候,点击视图查看账户余额。

#import "ViewController.h"
#import "Accounter.h"         // 引入账户类

@interface ViewController ()

@property (nonatomic, strong) Accounter *accounter;  // 账户

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.accounter = [[Accounter alloc] init];
    _accounter.balance = 1000;  // 账户初始余额1000
    [self testMultiThread];     // 多线程存钱/取钱
}

// 存钱线程函数
- (void)saveThreadFunc:(id)obj {
    for (int i = 0; i < 100000; i++) {
        _accounter.balance = _accounter.balance + 100;
        [NSThread sleepForTimeInterval:0.0001];
    }
    
    NSLog(@"存钱线程[%@] 执行结束", obj);
}

// 取钱线程函数
- (void)withdrawThreadFunc:(id)obj {
    for (int i = 0; i < 100000; i++) {
        _accounter.balance = _accounter.balance - 100;
        [NSThread sleepForTimeInterval:0.0001];
    }
    
    NSLog(@"取钱线程[%@] 执行结束", obj);
}

// 多线程存钱/取钱
- (void)testMultiThread {
    for (int i = 0; i < 10; i++) {
        NSNumber *number = [NSNumber numberWithInt:i]; // 线程编号
        
        if (i % 2 == 0) {
            [NSThread detachNewThreadSelector:@selector(saveThreadFunc:) toTarget:self withObject:number];
        } else {
            [NSThread detachNewThreadSelector:@selector(withdrawThreadFunc:) toTarget:self withObject:number];
        }
    }
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"账户余额 = %d", _accounter.balance);
}

@end

打印输出:

2020-04-05 12:25:58.269626+0800 MultiThreadLockDemo[2394:47732] 存钱线程[6] 执行结束
2020-04-05 12:25:58.269632+0800 MultiThreadLockDemo[2394:47733] 取钱线程[7] 执行结束
2020-04-05 12:25:58.271439+0800 MultiThreadLockDemo[2394:47727] 取钱线程[1] 执行结束
2020-04-05 12:25:58.274413+0800 MultiThreadLockDemo[2394:47729] 取钱线程[3] 执行结束
2020-04-05 12:25:58.274990+0800 MultiThreadLockDemo[2394:47730] 存钱线程[4] 执行结束
2020-04-05 12:25:58.275353+0800 MultiThreadLockDemo[2394:47734] 存钱线程[8] 执行结束
2020-04-05 12:25:58.276267+0800 MultiThreadLockDemo[2394:47726] 存钱线程[0] 执行结束
2020-04-05 12:25:58.277008+0800 MultiThreadLockDemo[2394:47731] 取钱线程[5] 执行结束
2020-04-05 12:25:58.278642+0800 MultiThreadLockDemo[2394:47735] 取钱线程[9] 执行结束
2020-04-05 12:25:58.282194+0800 MultiThreadLockDemo[2394:47728] 存钱线程[2] 执行结束
2020-04-05 12:27:39.032068+0800 MultiThreadLockDemo[2394:47529] 账户余额 = -13300

余额竟然是-13300?
问题在于这两个语句
(1)_accounter.balance = _accounter.balance + 100;
(2)_accounter.balance = _accounter.balance - 100;
当一个线程取得_accounter.balance的值,准备进行加减操作的时候,_accounter.balance实际是已经被别的线程赋上新的值了,而该线程拿到了旧的值。
那么如何保证线程操作_accounter.balance的时候,其他线程不能操作。除了@synchronized之外,咱么可以使用NSLock加锁
重新修改一下ViewController.m,加入锁操作

#import "ViewController.h"
#import "Accounter.h"         // 引入账户类

@interface ViewController ()

@property (nonatomic, strong) Accounter *accounter;  // 账户
@property (nonatomic, strong) NSLock *accounterLock; // 账户锁

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.accounter = [[Accounter alloc] init];
    _accounter.balance = 1000;               // 账户初始余额1000
    _accounterLock = [[NSLock alloc] init];  // 账户锁
    [self testMultiThread];                  // 多线程存钱/取钱
}

// 存钱线程函数
- (void)saveThreadFunc:(id)obj {
    for (int i = 0; i < 100000; i++) {
        [_accounterLock lock];
        _accounter.balance = _accounter.balance + 100;
        [_accounterLock unlock];
        [NSThread sleepForTimeInterval:0.0001];
    }
    
    NSLog(@"存钱线程[%@] 执行结束", obj);
}

// 取钱线程函数
- (void)withdrawThreadFunc:(id)obj {
    for (int i = 0; i < 100000; i++) {
        [_accounterLock lock];
        _accounter.balance = _accounter.balance - 100;
        [_accounterLock unlock];
        [NSThread sleepForTimeInterval:0.0001];
    }
    
    NSLog(@"取钱线程[%@] 执行结束", obj);
}

// 多线程存钱/取钱
- (void)testMultiThread {
    for (int i = 0; i < 10; i++) {
        NSNumber *number = [NSNumber numberWithInt:i]; // 线程编号
        
        if (i % 2 == 0) {
            [NSThread detachNewThreadSelector:@selector(saveThreadFunc:) toTarget:self withObject:number];
        } else {
            [NSThread detachNewThreadSelector:@selector(withdrawThreadFunc:) toTarget:self withObject:number];
        }
    }
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"账户余额 = %d", _accounter.balance);
}

@end

打印输出:

2020-04-05 12:41:40.592584+0800 MultiThreadLockDemo[2643:55872] 存钱线程[8] 执行结束
2020-04-05 12:41:40.592859+0800 MultiThreadLockDemo[2643:55869] 取钱线程[5] 执行结束
2020-04-05 12:41:40.593439+0800 MultiThreadLockDemo[2643:55865] 取钱线程[1] 执行结束
2020-04-05 12:41:40.595160+0800 MultiThreadLockDemo[2643:55868] 存钱线程[4] 执行结束
2020-04-05 12:41:40.595194+0800 MultiThreadLockDemo[2643:55873] 取钱线程[9] 执行结束
2020-04-05 12:41:40.597746+0800 MultiThreadLockDemo[2643:55866] 存钱线程[2] 执行结束
2020-04-05 12:41:40.597930+0800 MultiThreadLockDemo[2643:55871] 取钱线程[7] 执行结束
2020-04-05 12:41:40.600022+0800 MultiThreadLockDemo[2643:55870] 存钱线程[6] 执行结束
2020-04-05 12:41:40.600148+0800 MultiThreadLockDemo[2643:55867] 取钱线程[3] 执行结束
2020-04-05 12:41:40.611717+0800 MultiThreadLockDemo[2643:55864] 存钱线程[0] 执行结束
2020-04-05 12:42:21.068827+0800 MultiThreadLockDemo[2643:55634] 账户余额 = 1000

OK,账户余额 = 1000

从atomic关键字说到多线程安全(内含iOS给代码加锁方法总结) atomic是什么 原子性:在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果声明属性时不显式地声明nonatomic关键字,那这个属性就是“原子的”(atomic)。如果属性具备nonatomic特质,则不使用同步锁。 atomic 和 nonatomic这对属性关键字是和线程安全挂钩的,虽然 atomic 属性关键字会给该 property 的 gett... 阅读详情

相关推荐

NSLock和@synchronized

通过简单的例子来说明NSLock和@synchronized的执行和加锁流程

iOS底层系列之<40>--多线程<十>-锁<6>NSLock、NSRecursiveLock、NSConditionLock

OC常用对象锁

JH_Cao的博客 429

一、Abaqus CAE 入门操作(薄膜应力计算)

一、Abaqus CAE 入门操作(薄膜应力计算)

A20802013的博客 4365

IOS开发之NSLock 的使用

// NSLock的执行原理: // 某个线程A调用lock方法。这样,NSLock将被上锁。可以执行“关键部分”,完成后,调用unlock方法。 // 如果,在线程A 调用unlock方法之前,另一个线程B调用了同一锁对象的lock方法。那么,线程B只有等待。直到线程A调用了unlock。 NSLock* _lock = [[NSLock alloc] init

jscjxysx的专栏 2869

Cobalt Strike4.0安装包(内附中文版)

1.什么是 Cobalt Strike Cobalt Strike 是一个为对手模拟和红队行动而设计的平台,主要用于执行有目标的攻击和模拟高级威胁 者的后渗透行动。 Cobalt Strike已经不再使用MSF而是作为单独的平台使用,它分为客户端与服务端,服务端是一个,客户端可以有多个,可被团队进行分布式协团操作。集成了端口转发、扫描多模式端口Listener、Windows exe程序生成、W...

梦之序章的博客 2万+

【脑电信号处理与特征提取】P2-夏晓磊:脑电的神经起源与测量

ElectroEncephaloGraphyTherefore, EEG produces a graphed representation of the electrical activity occurring in a person’s brain.(把一个人的大脑中的电活动画出来)脑电头皮表面记录到的大脑活动产生的电信号(微伏)。(记录位置:硬脑膜/大脑皮层表面- ECoG,神经元群- LFP与MUR/MUA:活动位置:心电、眼电、肌电等)脑电图电压随时间变化的波形图。

m0_51474171的博客 1893

iOS底层探索之多线程(十六)——锁分析(NSLock、NSCondtion、NSRecursiveLock、NSCondition)

iOS 开发,各种锁你了解多少?NSLock、NSCondtion、NSRecursiveLock… 回顾 在之前的一篇博客中,介绍了锁的种类,在上一篇博客中已经对@synchronized锁进行了源码分析,还有其他的一些锁没有介绍,那么本篇博客就分析一下其他的一些锁! iOS底层探索之多线程(一)—进程和线程 iOS底层探索之多线程(二)—线程和锁 iOS底层探索之多线程(三)—初识GCD iOS底层探索之多线程(四)—GCD的队列 iOS底层探索之多线程(五)—GCD不同队列源码分析 iOS底层探索之

俊而不逊的博客 921

达梦数据库集群部署(主备)

达梦数据库集群部署(主备)

m0_71845127的博客 1460

iOS 中常见的几种锁-代码示例

iOS 中常见的几种锁介绍-示例 常用的各类锁性能比较 文中Demo 均实现在 XWInterviewDemos 1. iOS中的互斥锁 在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象。 1.1 @synchronized (self) - (void)lock1 { @syn...

weixin_34366546的博客 340

PLC的自抗扰控制(ADRC)算法

1、自抗扰控制算法,网上很多文章有所讲解,大家也可以关注韩京清教授的论文和书籍,这里就不赘述了,下面给出梯形图+SCL代码。 1、跟踪微分器 2、线性控制率 3、博图SCL控制代码 4、ADRC控制算法的所有公式汇总 ......

RXXW_Dor的博客 3852

ADS基础教程12 - 参数扫描

在硬件设计、仿真以及调试阶段,很多时候需要找到一个合理的参数来使设计处于最优状态。前面所讲的调优方式是其中的最直接的手段。因此,本文将介绍ADS中如何指定元器件的参数为变量,并可以对变量设置相应的约束条件,来实现的变量进行多组参数的仿真结果的展示。在图形显示界面,添加一个Plot,并添加参数结果。此时,结果中会显示出所有的扫描结果。参数扫描的要素包含:新建变量、变量参数设置、扫描模型设置三个方面。如果找不到该图标,在菜单栏单击右键,弹出的对话框将。,弹出的选项卡中,将添加两个变量。点击菜单栏的仿真按钮。

XZ_ZC的博客 8156

iOS多线程---常用的几种锁

我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,这就是锁。线程安全措施有:atomic、@synchronize(对象)、NSLock、NSRecursiveLock递归锁、NSCoditionLock(条件锁)、NSCondition、dispatch_semaphore、OSSpinLock(自旋锁,已弃用)、os_unfair_lock、pthread_mutex 、dispatch_once。

旭日的博客 1248

一台NAS两个系统:飞牛nas上完美运行群晖DSM?(飞牛nas+群晖nas套娃安装实操)

想在飞牛NAS上体验群晖DSM系统?💡 本文详细记录了飞牛nas上部署群晖的完整过程,从镜像转换到系统安装,每一步都有详细说明 🖥️,让你在不增加硬件成本的情况下,轻松实现一套硬件、多种系统的灵活部署 ✅

XiaoqiangClub的博客 2364

iOS 中的NSLock、 NSRecursiveLock、 NSCondition

iOS中的锁 第一篇博客很是忐忑,废话不多说。本篇博客借鉴于《高性能iOS 开发》 NSLock 这是一种低端锁。一旦获取锁,执行则进入临界区,且不会允许超过一个线程并行执行。释放锁则标记临界区结束。 @interface ThreadSafeClass () { NSLock *_lock; } @end @implementation ThreadSafeClass - (...

decadent_的博客 3621

量子编程专业权威教程(十四):Shor 算法

本文系统阐述了Shor算法的原理与实现,重点解析了将大数分解问题转化为周期寻找问题的数论基础,以及模幂运算量子电路的设计方法。通过以N=15为例的完整算法流程演示,展示了量子计算在因数分解问题上的指数级优势。文章详细拆解了受控幺正操作构建、量子傅里叶变换应用等关键技术环节,并提供了可复现的Qiskit代码实现。同时指出了当前量子硬件在比特数、相干时间和错误率等方面面临的工程挑战,这些限制使得分解大整数仍需长期技术突破。该研究为理解量子计算优势提供了典型范例,对后量子密码学发展具有重要启示意义。

分享知识,拥抱变化 797

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

iOS多线程同步锁

@synchronized@synchronized()是在OC代码中创建一个互斥锁非常方便的方法。@synchronized指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)。然而在这种情况下,你不需要直接创建一个互斥锁或锁对象。相反,你只需要简单的使用OC对象作为锁的令牌,如下面例子所示:- (void)myMethod:(id)anObj { @synchroni

Bmmboo的专栏 713

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【atomic】再谈从atomic关键字说到多线程安全(内含iOS给代码加锁方法总结)

再谈从atomic关键字说到多线程安全(内含iOS给代码加锁方法总结) atomic是什么 原子性:在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果声明属性时不显式地声明nonatomic关键字,那这个属性就是“原子的”(atomic)。如果属性具备nonatomic特质,则不使用同步锁。 atomic 和 nonatomic这对属性关键字是和线程安全挂钩的,虽然 atomic 属性关键字会给该 property 的 getter和setter方法加锁,但它也不能保

allanGold 1537

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【转】Object-C 多线程中锁的使用-NSLock

在多线程的编程环境中,锁的使用必不可少! 于是,今天来总结一下为共享资源加锁的操作方法。 一、使用synchronized方式 //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ @synchronized(_...

LTH1218的博客 190

iOS 中几种常用的锁总结

多线程编程中,应该尽量避免资源在线程之间共享,以减少线程间的相互作用。 但是总是有多个线程相互干扰的情况(如多个线程访问一个资源)。在线程必须交互的情况下,就需要一些同步工具,来确保当它们交互的时候是安全的。 锁是线程编程同步工具的基础。iOS开发中常用的锁有如下几种: @synchronized NSLock 对象锁 NSRecursiveLock 递归锁 NSConditionLoc...

x32sky的专栏 800

iOS OC中多线程总结

1. 进程(process): 系统中正在运行的一个程序的实例,具有一定的独立功能,是线程的容器。 2.线程(thread): 线程是进程执行的最小单位,一个进程中至少包含一个线程(主线程),进程中任务都在线程中执行(主线程或子线程)。 系统中正在运行的每一个应用程序都是一个 进程(Process) ,每个进程系统都会分配给它独立的内存运行。也就是说,在iOS系统中中,每一个应用都是一个进程。 一个进程的所有任务都在 线程(Thread)...

程序猿老樊的博客 2297

IOS中多线程的同步方法

一、使用synchronized方式     //线程1     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{         @synchronized(_myLockObj){             [obj1 method1];

骑着蜗牛找马儿 786

iOS边城之多线程并发编程

参考:官方 OS X和iOS中的多线程技术 基本每门语言都有多线程这个技术点,多线程是为了实现并发执行,可以理解为一个系统进程是由一个或多个线程组成的。iOS中创建线程的方式简单到可以直接调用对象的方法来实现,下面我们来看看。   调用NSObject方法实现多线程 NSObject提供了以 performSelector为前缀的一系列方法。它允许用户在指定的线程、什么时间执行某个

mokai 2027

iOS概念攻坚之路(五):线程同步方案

前言 多线程编程所处的环境是一个复杂的环境,线程之间穿插执行,需要使用一定的手段来保证程序的正确运行,这个手段就是同步。这篇文章分了两个部分,第一部分会先介绍同步的概念,第二部分是 iOS 中能使用到的同步方案的一个分析以及具体如何使用。 线程同步的概念 为什么要同步 线程之间的关系是合作关系,既然是合作,那就得有某种约定的规则,否则合作就会出现问题。例如,第一个线程在执行了一些操作后想检查当前的...

weixin_34128839的博客 276

iOS 线程同步与锁

线程同步说到多线程就不得不提多线程的锁机制,多线程操作过程中往往是多个线程并发执行的,同一个资源可能被多个线程同时访问,造成资源抢夺,这个时候如果没有锁机制会造成很大的问题。举个例子比如买票系统比如只剩下最后一张票但是又100线程进入购票环节,每个线程处理完票数都要减1,100个线程处理完以后票数为-99,这肯定是不对的。 因此要解决资源抢夺问题在iOS中有两种方法:一种是NSLock同步锁,另一

woshijunjunstudy的博客 303

iOS线程同步和锁实例详解及总结

应用程序里面多个线程的存在引发了多个执行线程安全访问资源的潜在问题。两个线程同时修改同一资源有可能以意想不到的方式互相干扰。 iOS 提供了你可以使用的多个同步工具,从提供互斥访问你程序的有序的事件的工具等。以下个部分介绍了这些工具和如何在代码中使用他们来影响安全的访问程序的资源。 我们通过同一个例子来说明这些锁,当两个线程同时操作一个可变数组时,一个线程添加数据,一个线程删除数据,类似一个生产消...

小T是我 1081

iOS多线程与锁

iOS中线程同步方案浅谈

weixin_41605583的博客 814
上一篇: 多线程同步之@synchronized实战例子
下一篇: iOS Base64编码解码的两种方法
数智客栈
博客等级 码龄17年 5699粉丝 89原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值