线程的锁

  1. NSLock
    • NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常使用的,除lock和unlock外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),并不会阻塞线程,直接返回NO。后一个方法则会在指定的Date之前尝试加锁,如果在指定的时间内都不能加锁,则返回NO
  2.  synchronized(互斥锁)
    • synchronized会创建一个异常捕获handler和一些内部的锁,所以使用@synchronized替换普通锁的代价是要付出更多的时间消耗
    • 创建给给@synchronized指令的对象是一个用来区别保护块的唯一标识符。如果你在两个不同的线程里面执行上述方法,每次在一个线程传递了一个不同的对象给anObj参数,那么每次都将会拥有它的锁,并持续处理,中间不会被其他线程阻塞。然而如果你传递的是同一个对象,那么多个线程中的一个线程会首先获得该锁,而其他线程将会被阻塞直到第一个线程完成它的临界区
    • 作为一个预防措施。@synchronized块隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁,这就意味着为了使用@synchronized指令,你必须在你的代码中启用异常处理。如果你不想让隐式的异常处理例程带来额外的开销,那么可以使用其他的锁
  3. atomic
    • atomic只是给成员变量的set和get方法加了一个锁,防止多线程一直去读写这个成员变量。但这也仅仅是对读写的锁定,并不是线程安全。而且使用atomic比nonatomic慢了将近20倍
  4. OSSpinlock
    • 自旋锁
    • 耗时最少
    • 自旋锁几乎不进入内核,仅仅是重新加载自旋锁
    • 如果自旋锁被占用时间在一百纳秒以内,性能还是比较高的,因为减少了代价较高的系统调用和一系列的上下文切换
    • 但是该锁不是万能的,如果该锁占用的时间比较多的时候,使用该锁会导致占用的cpu较多
  5. pthread_mutex
    • 是底层的API,在各种加锁方式中属于性能比较高的
    • 如果自旋锁占用的时间比较多,那么使用pthread是一个不错的选择
  6. NSConditionLock(条件锁)
    • 条件锁与特定的与用户定义的条件有关,它可以确保一个线程可以获取满足一定条件的锁
    • 内部涉及到信号量机制,一旦一个线程获取锁以后,它可以放弃锁并设置相关条件,这时候其他锁竞争该锁
    • 线程之间的竞争激烈,涉及到条件锁检测、线程间通信、系统调用,上下文切换比较频繁
  7. NSRecursiveLock递归锁
    • NSRecursiveLock实际上定义的是一个递归锁,这个锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或者递归操作中
  8. 总结:
    • 如果只是粗略的使用锁,不考虑性能可以使用synchronized
    • 如果对效率有较高的要求,采用OSSpinLock
    • 因为pthread的锁也是使用OSSpinLock实现的,而且在OSSpinLock的实现过程中,并没有进入系统kernel,使用OSSpinLock可以节省系统调用和上下文切换
    • NSLock/NSConditionLock/NSRecursive耗时接近。220ms左右
    • dispatch_barrier_async的性能并没有我们想象中的纳闷好,这与线程同步调度开销有关

猜你喜欢

转载自blog.csdn.net/qq_35726305/article/details/80569310
今日推荐