对于多线层的安全一直都是面试的重点,面试官一般会问线程安全,你会从那些角度去解决这个问题?
这里我说一下我的拙见,如果有更好的还请补充,不喜勿喷,谢谢!
对于线程安全,
1.首先可以使用noatomic,使用这个属性就会对该属性的setter方法加锁,这样的话可以保证线程的安全,但是失去了多线层的优势;
2.使用线程锁来保证同时只有一个线程能对数组进行写操作;
3.使用串行队列保证线程安全;
4.使用dispatch_notify来保证线程的执行顺序;
5.使用dipatch_barrier些操作和dispatch_asyn读操作;
首先看一段代码:
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-1");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-2");
});
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@"dispatch-barrier");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-3");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"dispatch-4");
});
这里dispatch_barrier的方法会在他之前的子线层dispatch_async执行完毕后再去执行,等到dispatch_barrier执行完成后,就恢复原来的操作,其实这里我们可以在dispatch_async方法里面进行读操作,然后再dispatch_barrier里面进行写操作,这样就可以保证线程安全以及利用多线层的优势了;
可变数组NSMuatbleArray是线程安全的吗?
下面咱们来看一下NSMutableArray线程安全的实现
1 继承 NSMutableArray创建NSKSafeMutableArray在这个地方遇到了一些坑通过查阅文档发现问题所在:
在 Cocoa 中有一种奇葩的类存在 Class Clusters。面向对象的编程告诉我们:“类可以继承,子类具有父类的方法”。而 Cocoa 中的 Class Clusters 虽然平时表现的像普通类一样,但子类却没法继承父类的方法。 NSMutableArray就是这样的存在。为什么会这样呢?因为 Class Clusters 内部其实是由多个私有的类和方法组成。虽然它有这样的弊端,但是好处还是不言而喻的。例如,NSNumber 其实也是这种类,这样一个类可以把各种不同的原始类型封装到一个类下面,提供统一的接口。这正设计模式中的抽象工厂模式。
查看Apple的文档,要继承这样的类需要必须实现其primitive methods方法,实现了这些方法,其它方法便都能通过这些方法组合而成。比如需要继承NSMutableArray就需要实现它的以下primitive methods:- (void)addObject:(id)anObject;- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;- (void)removeLastObject;- (void)removeObjectAtIndex:(NSUInteger)index;- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;1234512345和NSArray的primitive methods:- (NSUInteger)count;- (id)objectAtIndex:(NSUInteger)index;12122 NSKSafeMutableArray.h 的实现如下#import "NSKSafeMutableArray.h"@interface NSKSafeMutableArray(){ CFMutableArrayRef _array;}@end@implementation NSKSafeMutableArray- (id)init{ return [self initWithCapacity:10];}- (id)initWithCapacity:(NSUInteger)numItems{ self = [super init]; if (self) { _array = CFArrayCreateMutable(kCFAllocatorDefault, numItems, &kCFTypeArrayCallBacks); } return self;}- (NSUInteger)count { __block NSUInteger result; dispatch_sync(self.syncQueue, ^{ result = CFArrayGetCount(_array); }); return result;}- (id)objectAtIndex:(NSUInteger)index { __block id result; dispatch_sync(self.syncQueue, ^{ NSUInteger count = CFArrayGetCount(_array); result = indexcount) {
blockindex = count;
}
CFArrayInsertValueAtIndex(_array, index, (__bridge const void *)anObject);
});
}
- (void)removeObjectAtIndex:(NSUInteger)index
{
dispatch_barrier_async(self.syncQueue, ^{
NSUInteger count = CFArrayGetCount(_array);
NSLog(@"count:%lu,index:%lu",(unsigned long)count,(unsigned long)index);
if (index < count) {
CFArrayRemoveValueAtIndex(_array, index);
}
});
}
- (void)addObject:(id)anObject
{
dispatch_barrier_async(self.syncQueue, ^{
if (!anObject)
return;
CFArrayAppendValue(_array, (__bridge const void *)anObject);
});
}
- (void)removeLastObject {
dispatch_barrier_async(self.syncQueue, ^{
NSUInteger count = CFArrayGetCount(_array);
if (count > 0) {
CFArrayRemoveValueAtIndex(_array, count-1);
}
});
}
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
dispatch_barrier_async(self.syncQueue, ^{
if (!anObject)
return;
NSUInteger count = CFArrayGetCount(_array);
CFArraySetValueAtIndex(_array, index, (__bridge const void*)anObject);
});
}
#pragma mark Optional
- (void)removeAllObjects
{
dispatch_barrier_async(self.syncQueue, ^{
CFArrayRemoveAllValues(_array);
});
}
- (NSUInteger)indexOfObject:(id)anObject{
if (!anObject)
return NSNotFound;
__block NSUInteger result;
dispatch_sync(self.syncQueue, ^{
NSUInteger count = CFArrayGetCount(_array);
result = CFArrayGetFirstIndexOfValue(_array, CFRangeMake(0, count), (__bridge const void *)(anObject));
});
return result;
return result;
}
#pragma mark - Private
- (dispatch_queue_t)syncQueue {
static dispatch_queue_t queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("com.kong.NSKSafeMutableArray", DISPATCH_QUEUE_CONCURRENT);
});
return queue;
}
@end
3 调用
- (void)viewDidLoad {
[super viewDidLoad];
NSKSafeMutableArray *safeArr = [[NSKSafeMutableArray alloc] init];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for ( int i = 0; i < 5; i ++) {
dispatch_async(queue, ^{
NSLog(@"添加第%d个",i);
[safeArr addObject:[NSString stringWithFormat:@"%d",i]];
});
dispatch_async(queue, ^{
NSLog(@"删除第%d个",i);
[safeArr removeObjectAtIndex:i];
});
}
// Do any additional setup after loading the view, typically from a nib.
}