美文网首页
NSMutableArray 线程安全方案

NSMutableArray 线程安全方案

作者: TaoGeNet | 来源:发表于2020-03-01 21:35 被阅读0次

    线程安全的NSMutableArray

    NSMutableArray本身是线程不安全的。多线程访问NSMutableArray 会出现异常和Crash

    一、不能使用atomic 修饰属性

    原因:atomic 的内存管理语义是原子性的,仅保证了属性的setter和getter方法是原子性的,是线程安全的,但是属性的其他方法,不能保证线程安全。同时atomic 效率低,编程时慎用。

    二、打造线程安全的NSMutableArray

    1、读写数组时加锁
    2、读写数组放到串行队列中。
    3、使用并发队列,结合GCD的拦珊块(barrier)来实现线程同步。

    第三种实现方式:

    @interface QSThreadSafeMutableArray : NSMutableArray
    
    @end
    
    //QSThreadSafeMutableArray.m
    #import "QSThreadSafeMutableArray.h"
    @interface QSThreadSafeMutableArray()
    
    @property (nonatomic, strong) dispatch_queue_t syncQueue;
    @property (nonatomic, strong) NSMutableArray* array;
    
    @end
    
    @implementation QSThreadSafeMutableArray
    
    #pragma mark - init 方法
    - (instancetype)initCommon{
    
        self = [super init];
        if (self) {
            //%p 以16进制的形式输出内存地址,附加前缀0x
            NSString* uuid = [NSString stringWithFormat:@"com.jzp.array_%p", self];
            //注意:_syncQueue是并行队列
            _syncQueue = dispatch_queue_create([uuid UTF8String], DISPATCH_QUEUE_CONCURRENT);
        }
        return self;
    }
    
    - (instancetype)init{
    
        self = [self initCommon];
        if (self) {
            _array = [NSMutableArray array];
        }
        return self;
    }
    
    //其他init方法略
    
    #pragma mark - 数据操作方法 (凡涉及更改数组中元素的操作,使用异步派发+栅栏块;读取数据使用 同步派发+并行队列)
    - (NSUInteger)count{
    
        __block NSUInteger count;
        dispatch_sync(_syncQueue, ^{
            count = _array.count;
        });
        return count;
    }
    
    - (id)objectAtIndex:(NSUInteger)index{
    
        __block id obj;
        dispatch_sync(_syncQueue, ^{
            if (index < [_array count]) {
                obj = _array[index];
            }
        });
        return obj;
    }
    
    - (NSEnumerator *)objectEnumerator{
    
        __block NSEnumerator *enu;
        dispatch_sync(_syncQueue, ^{
            enu = [_array objectEnumerator];
        });
        return enu;
    }
    
    - (void)insertObject:(id)anObject atIndex:(NSUInteger)index{
    
        dispatch_barrier_async(_syncQueue, ^{
            if (anObject && index < [_array count]) {
                [_array insertObject:anObject atIndex:index];
            }
        });
    }
    
    - (void)addObject:(id)anObject{
    
        dispatch_barrier_async(_syncQueue, ^{
            if(anObject){
               [_array addObject:anObject];
            }
        });
    }
    
    - (void)removeObjectAtIndex:(NSUInteger)index{
    
        dispatch_barrier_async(_syncQueue, ^{
    
            if (index < [_array count]) {
                [_array removeObjectAtIndex:index];
            }
        });
    }
    
    - (void)removeLastObject{
    
        dispatch_barrier_async(_syncQueue, ^{
            [_array removeLastObject];
        });
    }
    
    - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject{
    
        dispatch_barrier_async(_syncQueue, ^{
            if (anObject && index < [_array count]) {
                [_array replaceObjectAtIndex:index withObject:anObject];
            }
        });
    }
    
    - (NSUInteger)indexOfObject:(id)anObject{
    
        __block NSUInteger index = NSNotFound;
        dispatch_sync(_syncQueue, ^{
            for (int i = 0; i < [_array count]; i ++) {
                if ([_array objectAtIndex:i] == anObject) {
                    index = i;
                    break;
                }
            }
        });
        return index;
    }
    
    - (void)dealloc{
    
        if (_syncQueue) {
            _syncQueue = NULL;
        }
    }
    @end
    

    参考:
    NSMutableArray使用中忽视的问题
    dispatch_async与dispatch_sync区别
    GCD有关问题:dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"Hello ?");}); 死锁的原因
    dispatch_barrier_sync 和dispatch_barrier_async的区别
    iOS多线程-GCD之串行队列和并行队列

    相关文章

      网友评论

          本文标题:NSMutableArray 线程安全方案

          本文链接:https://www.haomeiwen.com/subject/kufhkhtx.html