面试的时候被问到了一个问题,NSMutableArray是怎么实现的?既然是一个数组,那么内存大小不是已经确定了吗,为什么还可以往里面添加呢?
如何保证NSMutableArray的线程安全?
简单来说,线程安全就是多个线程访问同一段代码,程序不会异常、不Crash。而编写线程安全的代码主要依靠线程同步。
1.不用atomic属性,atomic属性只能保证setter,getter方法是线程安全的,而可变数组的其它方法并不能保证是原子的,因此也就无法保证是线程安全的。使用atomic修饰属性的代价很大,执行效率很慢。
2.使用gcd,在“最后一次使用gcd”这个文章里我写到了关于gcd_barrier这个方法的作用。这里就派上了用场。写操作不能和其他的写操作或者包含读操作的某些其它操作并行执行,但是多个读操作是可以并行执行的。
可以用并发队列存储多个读操作,然后栅栏函数执行写操作,写操作执行完之后可以继续用并发队列执行读操作,和“最后一次使用gcd”这个文章里写的一样。
⚠️:这里的并发队列只能是手动创建的并发队列,不能是全局并发队列。
利用这个思想设计线程安全的NSMutableArray的策略:
凡涉及到修改数组中元素的,都用栅栏函数,异步函数+并发队列。比如说增加数据,删除数据,修改数据等等。虽然这里用了异步函数加并发队列,但是栅栏函数里的操作是按顺序执行的,不会造成线程不安全。
凡涉及到单独的读取操作,比如说遍历数组,读取数据等就用同步函数+并发队列。⚠️:这里就是说读取数据的时候如果用了异步函数+并发队列,那么读数据的操作就是无序的,会造成线程的不安全,所以应该用同步函数,保证读取操作的执行顺序。
参考文章:
iOS实录12:NSMutableArray使用中忽视的问题
这里也可以说是gcd的一个应用。