锁 是什么意思?

  • 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生。

  • 这里顺便提一下,上锁的两种方式trylock和lock使用场景:

当前线程锁失败,也可以继续其它任务,用 trylock 合适

当前线程只有锁成功后,才会做一些有意义的工作,那就 lock,没必要轮询 trylock

注:以下大部分锁都会提供trylock接口,不再作解释

性能图

<准备操作>

测试代码

#define RHTICK   NSDate *startTime = [NSDate date];

#define RHTOCK   NSLog(@"==========Time: %f", -[startTime timeIntervalSinceNow]);

NSUInteger count = 1000*10000;//执行一千万次

RHTICK

for(int i=0; i<count; i++) {

加锁

解锁

}

RHTOCK

注:测试中执行时间会波动,所以我取的平均值.

一、OSSpinLock (自旋锁)

测试中效率最高的锁, 不过经YYKit作者确认, OSSpinLock已经不再线程安全,OSSpinLock有潜在的优先级反转问题.不再安全的 OSSpinLock;

  • 0.097348s

需要导入头文件

#import <libkern/OSAtomic.h>

// 初始化

OSSpinLock spinLock = OS_SPINLOCK_INIT;

// 加锁

OSSpinLockLock(&spinLock);

// 解锁

OSSpinLockUnlock(&spinLock);

// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO

OSSpinLockTry(&spinLock)

/*

注:苹果爸爸已经在iOS10.0以后废弃了这种锁机制,使用os_unfair_lock 替换,

顾名思义能够保证不同优先级的线程申请锁的时候不会发生优先级反转问题.

*/

二、os_unfair_lock(自旋锁)

  • 0.171789s

需要导入头文件

#import <os/lock.h>

// 初始化

os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT;

// 加锁

os_unfair_lock_lock(&unfair_lock);

// 解锁

os_unfair_lock_unlock(&unfair_lock);

// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO

os_unfair_lock_trylock(&unfair_lock);

/*

注:解决不同优先级的线程申请锁的时候不会发生优先级反转问题.

不过相对于 OSSpinLock , os_unfair_lock性能方面减弱了许多.

*/

三、dispatch_semaphore (信号量)

  • 0.155043s

// 初始化

dispatch_semaphore_t semaphore_t = dispatch_semaphore_create(1);

// 加锁

dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER);

// 解锁

dispatch_semaphore_signal(semaphore_t);

/*

注: dispatch_semaphore  其他两个功能

1.还可以起到阻塞线程的作用.

2.可以实现定时器功能,这里不做过多介绍.

*/

四、pthread_mutex(互斥锁)

  • 0.262592s

需要导入头文件

#import <pthread/pthread.h>

// 初始化(两种)

1.普通初始化

pthread_mutex_t mutex_t;

pthread_mutex_init(&mutex_t, NULL);

2.宏初始化

pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;

// 加锁

pthread_mutex_lock(&mutex_t);

// 解锁

pthread_mutex_unlock(&mutex_t);

// 尝试加锁,可以加锁时返回的是 0,否则返回一个错误

pthread_mutex_trylock(& mutex_t)

五、NSLock(互斥锁、对象锁)

  • 0.283196s

// 初始化

NSLock *_lock = [[NSLock alloc]init];

// 加锁

[_lock lock];

// 解锁

[_lock unlock];

// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO

[_lock tryLock];

六、NSCondition(条件锁、对象锁)

  • 0.293046s

// 初始化

NSCondition *_condition= [[NSCondition alloc]init];

// 加锁

[_condition lock];

// 解锁

[_condition unlock];

/*

其他功能接口

wait 进入等待状态

waitUntilDate:让一个线程等待一定的时间

signal 唤醒一个等待的线程

broadcast 唤醒所有等待的线程

注: 所测时间波动太大, 有时候会快于 NSLock, 我取得中间值.

*/

七、NSConditionLock(条件锁、对象锁)

 

  • 0.950285s

// 初始化

NSConditionLock *_conditionLock = [[NSConditionLock alloc]init];

// 加锁

[_conditionLock lock];

// 解锁

[_conditionLock unlock];

// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO

[_conditionLock tryLock];

/*

其他功能接口

- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER; //初始化传入条件

- (void)lockWhenCondition:(NSInteger)condition;//条件成立触发锁

- (BOOL)tryLockWhenCondition:(NSInteger)condition;//尝试条件成立触发锁

- (void)unlockWithCondition:(NSInteger)condition;//条件成立解锁

- (BOOL)lockBeforeDate:(NSDate *)limit;//触发锁 在等待时间之内

- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//触发锁 条件成立 并且在等待时间之内

*/

八、NSRecursiveLock(递归锁、对象锁)

  • 0.473536s

// 初始化

NSRecursiveLock *_recursiveLock = [[NSRecursiveLock alloc]init];

// 加锁

[_recursiveLock lock];

// 解锁

[_recursiveLock unlock];

// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO

[_recursiveLock tryLock];

/*

注: 递归锁可以被同一线程多次请求,而不会引起死锁。

即在同一线程中在未解锁之前还可以上锁, 执行锁中的代码。

这主要是用在循环或递归操作中。

- (BOOL)lockBeforeDate:(NSDate *)limit;//触发锁 在等待时间之内

*/

九、@synchronized(条件锁)

  • 1.101924s

// 初始化

@synchronized(条件){

}

更多关于@synchronized;

十、pthread_mutex(recursive)(递归锁)

  • 0.372398s

// 初始化

pthread_mutex_t mutex_t;

pthread_mutexattr_t attr;

pthread_mutexattr_init(&attr); //初始化attr并且给它赋予默认pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //设置锁类型,这边是设置为递归锁

pthread_mutex_init(&mutex_t, &attr);

pthread_mutexattr_destroy(&attr); //销毁一个属性对象,在重新进行初始化之前该结构不能重新使用

// 加锁

pthread_mutex_lock(&mutex_t);

// 解锁

pthread_mutex_unlock(&mutex_t);

/*

注: 递归锁可以被同一线程多次请求,而不会引起死锁。

即在同一线程中在未解锁之前还可以上锁, 执行锁中的代码。

这主要是用在循环或递归操作中。

*/

性能总结

OSSpinLock                          0.097348s

dispatch_semaphore                  0.155043s

os_unfair_lock                      0.171789s

pthread_mutex                       0.262592s

NSLock                               0.283196s

pthread_mutex(recursive)            0.372398s

NSRecursiveLock                     0.473536s

NSConditionLock                     0.950285s

@synchronized                       1.101924s

注:建议正常锁功能用 pthread_mutex ,os_unfair_lock (适配低版本)

iOS 十种线程锁的更多相关文章

  1. iOS 多线程之线程锁Swift-Demo示例总结

    线程锁是什么 在前面的文章中总结过多线程,总结了多线程之后,线程锁也是必须要好好总结的东西,这篇文章构思的时候可能写的东西得许多,只能挤时间一点点的慢慢的总结了,知道了线程之后要了解线程锁就得先了解一 ...

  2. iOS 多线程的简单理解(4) 线程锁的简单使用

    要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全 推荐一个原文链接 是关于 线程锁的基本使用的  http://blog.csdn.net/qq_30513483/article/detai ...

  3. 谈谈iOS中的锁

    1 前言 近日工作不是太忙,刚好有时间了解一些其他东西,本来打算今天上午去体检,但是看看天气还是明天再去吧,也有很大一个原因:就是周六没有预约上!闲话少说,这里简单对锁来个简单介绍分享. 2 目录 第 ...

  4. 单例模式——使用GCD实现单例模式 & 非ARC单例模式 &使用GCD和线程锁实现单例模式-b

    1.单利模式概述 链接:  iOS开发懒汉模式&恶寒模式 2.使用GCD实现单利模式 2.1新建一个project,然后新建一个HMDataTool类展示GCD实现单例模式 #import & ...

  5. NSLock线程锁的使用测试

    测试1:NSLock线程锁是不是单例? 打印: 结论1:NSLock不是单例 测试2:同一个线程锁在不同的地方锁定,是否会有锁定两个? 打印为: 结论2:顺序打印,在不同的地方锁定也可以锁定. 测试3 ...

  6. day9---多线程,线程锁,队列

    进程.线程 http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 使用threading模块实现多线程编程[综述] Pyt ...

  7. python线程锁

    import time,threading balance = 0 lock = threading.Lock() def change_it(n): global balance balance = ...

  8. linux下使用线程锁互斥访问资源

    linux使用线程锁访问互斥资源: 1.线程锁的创建 pthread_mutex_t g_Mutex; 2.完整代码如下 #include <stdio.h> #include <s ...

  9. JAVA线程锁-读写锁

    JAVA线程锁,除Lock的传统锁,又有两种特殊锁,叫读写锁ReadWriteLock 其中多个读锁不互斥,读锁和写锁互斥,写锁和写锁互斥 例子: /** * java线程锁分为读写锁 ReadWri ...

随机推荐

  1. js 字符串相关函数

    https://www.jb51.net/article/74614.htm

  2. 记数问题(0)<P2013_1>

    记数问题 (count.cpp/c/pas) [问题描述]  试计算在区间1到n的所有整数中,数字x(0≤x≤9)共出现了多少次?例如,在1到11中,即在1.2.3.4.5.6.7.8.9.10.11 ...

  3. c++特有的bool变量和用const定义变量

    写再最前面:摘录于柳神的笔记: bool 变量有两个值, false 和 true ,以前⽤C语⾔的时候都是⽤ int 的 0 和 1 表示 false 和 true 的,现在C++⾥⾯引⼊了这个叫做 ...

  4. java记录1--接口

    接口(interface)定义:抽象方法和常量值的集合.本质上讲,接口是一种特殊的抽象类 ps:1.接口中定义的属性必须是public static final 的,定义的方法必须是public ab ...

  5. 【PAT甲级】1019 General Palindromic Number (20 分)

    题意: 输入两个正整数n和b(n<=1e9,2<=b<=1e9),分别表示数字的大小和进制大小,求在b进制下n是否是一个回文串,输出“Yes”or“No”,并将数字n在b进制下打印出 ...

  6. Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

    Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离.

  7. Lamda表达式学习笔记二

    Lamda表达式学习笔记二 lamda表达式----方法引用 上一篇讲到Lamda体就是对函数式接口方法的实现 ,在方法体中我们可能会引用其他方法实现逻辑,所以在lamda体中我们可以直接引用器方法 ...

  8. css元素隐藏方式

    1.opacity:设置一个元素的透明度 .hide {opacity: 0;} 2.visibility:设置一个元素可见\不可见.hide {visibility: hidden} .hide { ...

  9. Vue 路由组件

    目录 组件数据局部化处理 路由逻辑跳转 组件传参 父传子 子传父 组件的生命周期钩子 路由传参 全家配置自定义 CSS 与 js 总结: 组件数据局部化处理 不管页面组件还是小组件,都可能会被多次复用 ...

  10. 谁说5G网络无敌?第六代Wi-Fi表示不服

    导读 随着第五代移动通信技术(5G)正式商用,同属第五代的Wi-Fi技术(802.11ac)的处境就非常尴尬了,除了不存流量费用外,无论是网速.设备连接数还是网络延迟,5G都拥有秒杀802.11ac的 ...