首先,明确几个概念,原子性是什么?线程安全是什么?原子性是指一个事物的操作是不可分割的,要么都发生,要么都不发生。线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程,使程序功能正确完成。其实意思就是多线程情况下程序的执行顺序要有单一性和正确性。
atomic 原子属性
- 是默认的
- 只能说是set/get是安全的,但当进行其他操作的时候,线程并不是完全安全的
- 会保证 CPU 能在别的线程来访问这个属性之前,先执行完当前流程
- 速度不快,因为要保证操作整体完成
- set/get方法内部加锁
nonatomic 非原子属性
- 不是默认的
- 线程不安全
- 如有两个线程访问同一个属性,会出现无法预料的结果
- 更快
- set/get方法都不会加锁
苹果底层是atomic的setter/getter是os_unfair_lock,差点被苹果骗了!原来系统中自旋锁已经全部改为互斥锁实现了,只是名称一直没有更改。为了修复优先级反转的问题,苹果也只能放弃使用自旋锁,改用优化了性能的 os_unfair_lock
,实际测试两者的效率差不多。
(各类锁可以参考https://www.jianshu.com/p/938d68ed832c)
// getter
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
// ...
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// ...
}
// setter
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
// ...
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
// ...
}
using spinlock_t = mutex_tt<LOCKDEBUG>;
using mutex_t = mutex_tt<LOCKDEBUG>;
class mutex_tt : nocopy_t {
os_unfair_lock mLock; //处理了优先级的互斥锁
void lock() {
lockdebug_mutex_lock(this);
os_unfair_lock_lock_with_options_inline
(&mLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
}
void unlock() {
lockdebug_mutex_unlock(this);
os_unfair_lock_unlock_inline(&mLock);
}
}
注:atomic是Objc使用的一种线程保护技术,基本上来讲是防止在写未完成的时候另一个线程读取,造成的数据错误。而这种机制是非常耗费系统资源的,所以iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。而iOS开发中,普遍使用nonatomic也是基于性能这一点。
也可以看看这https://stackoverflow.com/questions/588866/whats-the-difference-between-the-atomic-and-nonatomic-attributes大佬们的理解!!