多线程系列面试题4 - 常见的锁有哪些,使用过么,简单说说

一般会在多线程里面引出锁相关的面试题,或者直接问,反正没啥区别

锁的出现就是为了应付多线程的弊端,也就是多个线程访问同一个资源,举个例子你在使用的时候另一个线程也在修改,当你再次访问这个变量的结果会发生差异,这种导致最终结果至少不是想要的结果

常见的锁:

OSSpinLock,os_unfair_lock 前者已经废弃,替换者是后者,是自旋锁

pthread_mutex,NSLock,NSRecursiveLock,NSCondition,NSConditionLock pthread_mutex一般不使用,会使用它的封装对像NSLock,这些是互斥锁

@synchronized swift没有,只能用底层来实现各类似的,是一种最简单的互斥锁,但swift无法使用,仅存的优势也不在了

还有一些可以当锁用的技术:

串行队列 不赘述了,处于同一队列肯定得一个个访问

信号量限制 同一时间的最大访问量,设置为1也能起到锁的作用

atomic 不建议用,后面单独说下

先举个多线程导致结果错误的例子:

 var money:Int = 100
 func saveMoney()
 {
     var oldMoney: Int = self.money
     sleep(UInt32(0.2)) //处理数据
     oldMoney += 60
     self.money = oldMoney
     print("加60个币,还剩\(oldMoney)币 - \(Thread.current)")
 }
 func drawMoney()
 {
     var oldMoney: Int = self.money
     sleep(UInt32(0.3)) //处理数据
     oldMoney -= 10
     self.money = oldMoney
     print("减去10个币,还剩\(oldMoney)币 - \(Thread.current)")
 }
 override func viewDidLoad() {
     DispatchQueue.global().async{
         for _ in 0..<10 {
             self.saveMoney()
         }
     }
     DispatchQueue.global().async{
         for _ in 0..<10 {
             self.drawMoney()
         }
}

 我这边跑出的最终结果是480,这明显是个错误的结果,不同的编译环境和电脑,这个结果也许不会相同,所以不必在意这个结果,只要确定是错的,就没问题了

os_unfair_lock

这是一个自旋锁,等待的线程会不停的循环

var lock = os_unfair_lock()
DispatchQueue.global().async{
    for _ in 0..<10 {
        os_unfair_lock_lock(&lock)
        self.saveMoney()
        os_unfair_lock_unlock(&lock)
    }
}
DispatchQueue.global().async{
    for _ in 0..<10 {
        os_unfair_lock_lock(&lock)
        self.drawMoney()
        os_unfair_lock_unlock(&lock)
    }
}

其实也简单,在会冲突的地方加锁就好了,同一个变量,肯定是同一把锁

 加60个币,还剩600币 - <NSThread: 0x600000c336c0>{number = 3, name = (null)}

log输出的结果就没问题了

NSLock

是一种互斥锁,这种锁不会循环等待,会直接休眠

let lock = NSLock()
DispatchQueue.global().async{
    for _ in 0..<10 {
        lock.lock()
        self.saveMoney()
        lock.unlock()
    }
}
DispatchQueue.global().async{
    for _ in 0..<10 {
        lock.lock()
        self.drawMoney()
        lock.unlock()
    }
}

单纯从使用上来说其实没有什么太大区别

NSRecursiveLock 

递归锁,也是封装的mutex的递归锁,听名字就知道是递归用的,作用就是允许单个线程的重复加锁

var num:Int = 100
var lock:NSLock = NSLock()
func test()
{
    lock.lock()
    if self.num > 1 {
        self.num -= 10
        print(self.num)
        self.test()
    }
    lock.unlock()
}

比如在递归里面,这样加锁unlock不可能有执行的时候,所以就卡在那了,这种情况有很多种解决方式递归锁就是其中一种

var num:Int = 100
var lock:NSRecursiveLock = NSRecursiveLock()
func test()
{
    lock.lock()
    if self.num > 1 {
        self.num -= 10
        print(self.num)
        self.test()
    }
    lock.unlock()
}

需要注意的点是,递归锁,允许单一线程给一把锁重复加锁

NSCondition

条件锁,是对mutex和cont的封装,相对于其它锁来说,这个锁用于线程间通讯更方便一些,用于普通的锁反而是浪费了点

var arr:[String] = []
var lock:NSCondition = NSCondition()
func task1(){
    lock.lock()
    /* 其它代码 */
    if self.arr.count != 10{
        lock.wait()
    }
    for i in self.arr{
        print(i)
    }
    lock.unlock()
    /* 其它代码 */
}
func task2(){
    /* 其它代码 */
    for i in 0..<10 {
        self.arr.append(String(i))
    }
    lock.signal()
    /* 其它代码 */
}
override func viewDidLoad() {
    DispatchQueue.global().async { //线程A
        /* 其它代码 */
        self.task1()
        /* 其它代码 */
    }
    DispatchQueue.global().async { //线程B
        /* 其它代码 */
        self.task2()
        /* 其它代码 */
    }
}

比如A线程的task1执行需要B线程task2处理好的数据才能执行,那么用condition就能很轻松的完成线程中的通讯

NSConditionLock

比NSCondition要更加强大,多了个条件值,可以定制多个条件,实现更复杂的线程间通讯

var lock:NSConditionLock = NSConditionLock(condition: 1)
lock.lock(whenCondition: 1)
lock.unlock(withCondition: 2)
lock.lock(whenCondition: 2)
lock.unlock(withCondition: 3)

具体就不详细赘述了,有一个条件值,只有满足条件才会继续往下走,起始值就是初始化时候的值,每次解锁重新指定新的值

@synchronized

这个只支持OC,不支持Swift

@synchronized(self){
    [self drawMoney];
}

用自身加锁,不用再创建锁对象,是OC里面最简单的加锁方式,所以使用很频繁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值