背景
我们日常,在我们的印象中原子性是和线程安全划等号的,事实确实是这样的,不要被一些标题党误导😂,说他不是线程安全是相对于整个对象的。
概念
维基百科的解释:线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程,使程序功能正确完成。其实意思就是多线程情况下程序的执行顺序要有单一性和正确性。
原子性:关于原子性可以看下这篇文章《关于原子性的理解》。
概括一下原子性就是保证一个操作的完整性(不可被打断),在我们oc中就是保证setter和getter操作的完整性。
结论:
那我们的结论是这样的:
用atomic修饰后,这个属性的setter、getter方法是线程安全的,但是对于整个对象来说不一定是线程安全的。
原因:
1.为什么setter、getter方法是线程安全的?
因为在setter和getter赋值取值的时候添加了自旋锁,不懂看这《oc中的线程锁》
// 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();
}
// ...
}
2.为什么说atomic没办法保证整个对象的线程安全,这里主要看一下网上主流的答案?
1.对于NSArray类型
@property(atomic)NSArray *array
我们用atomic修饰,数组的添加和删除并不是线程安全的,这是因为数组比较特殊,我们要分成两部分考虑,一部分是&array也就是这个数组本身,另一部分是他所指向的内存部分。atomic限制的只是&array部分,对于它指向的对象没有任何限制。
atomic表示,我TM也很冤啊!!!!
2.当线程A进行写操作,这时其他线程的读或者写操作会因为该操作而等待。当A线程的写操作结束后,B线程进行写操作,然后当A线程需要读操作时,却获得了在B线程中的值,这就破坏了线程安全,如果有线程C在A线程读操作前release了该属性,那么还会导致程序崩溃。所以仅仅使用atomic并不会使得线程安全,我们还要为线程添加lock来确保线程的安全。
个人觉得这个就有点杠精的意味了,atomic还要管到你方法外面去了?????不过面试人家问你还要这么答,要严谨!!