數(shù)組線程安全的思考NSMutableArray是線程不安全的,當有多個線程同時對數(shù)組進行操作的時候可能導致崩潰或數(shù)據(jù)錯誤汉操,下面是我對線程安全的幾個思路再来,希望由此能給你帶來一些思路,如果有錯誤的地方還希望大家能夠指出
1.對數(shù)組的讀寫都加鎖磷瘤,雖然數(shù)組是線程安全了芒篷,但失去了多線程的優(yōu)勢
2.然后又想可以只對寫操作加鎖然后定義一個全局變量來表示現(xiàn)在有沒有寫操作搜变,如果有寫操作就等寫完了在讀,那么問題來了如果一個線程先讀取數(shù)據(jù)緊接著一個線程對數(shù)組寫的操作梭伐,讀的時候還沒有加鎖同樣會導致崩潰或數(shù)據(jù)錯誤痹雅,這個方案pass掉
3.第三種方案說之前先介紹一下dispatch_barrier_async,dispatch_barrier_async 追加到 queue 中后糊识,會等待 queue 中的任務都結束后绩社,再執(zhí)行 dispatch_barrier_async 的任務,等 dispatch_barrier_async 的任務結束后赂苗,才恢復任務執(zhí)行愉耙, 用dispatch_async和dispatch_barrier_async結合保證NSMutableArray的線程安全,用dispatch_async讀和dispatch_barrier_async寫(add,remove,replace)拌滋,當有任務在讀的時候寫操作會等到所有的讀操作都結束了才會寫朴沿,同樣當有寫任務時,讀任務會等寫操作完了才會讀败砂,既保證了線程安全又發(fā)揮了多線程的優(yōu)勢赌渣,但還是有個不足,當我們重寫讀的方法時dispatch_async是另開辟線程去執(zhí)行的而且是立馬返回的昌犹,所以我們不能拿到執(zhí)行結果坚芜,需要去另寫一個方法來返回讀的結果,但是我們又不想改變調(diào)用者的習慣于是又想到了一下方案
4.用dispatch_sync和dispatch_barrier_async結合保證NSMutableArray的線程安全斜姥,dispatch_sync是在當前線程上執(zhí)行不會另開辟新的線程鸿竖,當線程返回的時候就可以拿到讀取的結果,我認為這個方案是最完美的選擇铸敏,既保證的線程安全有發(fā)揮了多線程的優(yōu)勢還不用另寫方法返回結果缚忧,完美~數(shù)組線程安全的實現(xiàn)下面咱們來看一下NSMutableArray線程安全的實現(xiàn)1 繼承 NSMutableArray創(chuàng)建NSKSafeMutableArray在這個地方遇到了一些坑通過查閱文檔發(fā)現(xiàn)問題所在:在 Cocoa 中有一種奇葩的類存在 Class Clusters。面向對象的編程告訴我們:“類可以繼承杈笔,子類具有父類的方法”闪水。而 Cocoa 中的 Class Clusters 雖然平時表現(xiàn)的像普通類一樣,但子類卻沒法繼承父類的方法蒙具。 NSMutableArray就是這樣的存在敦第。為什么會這樣呢?因為 Class Clusters 內(nèi)部其實是由多個私有的類和方法組成店量。雖然它有這樣的弊端,但是好處還是不言而喻的鞠呈。例如融师,NSNumber 其實也是這種類,這樣一個類可以把各種不同的原始類型封裝到一個類下面蚁吝,提供統(tǒng)一的接口旱爆。這正設計模式中的抽象工廠模式舀射。查看Apple的文檔,要繼承這樣的類需要必須實現(xiàn)其primitive methods方法怀伦,實現(xiàn)了這些方法脆烟,其它方法便都能通過這些方法組合而成。
比如需要繼承NSMutableArray就需要實現(xiàn)它的以下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;
NSArray的primitive methods:
- (NSUInteger)count;- (id)objectAtIndex:(NSUInteger)index;
# NSKSafeMutableArray.h 的實現(xiàn)如下
#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 調(diào)用
- (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.
}