多线层安全的考虑

2017-04-12  本文已影响69人  Jeff_Kitty

对于多线层的安全一直都是面试的重点,面试官一般会问线程安全,你会从那些角度去解决这个问题?

这里我说一下我的拙见,如果有更好的还请补充,不喜勿喷,谢谢!

对于线程安全,

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.

}

上一篇 下一篇

猜你喜欢

热点阅读