iOS - synchronized同步锁和dispatch_barrier应用

 

 

 

synchronized 实现同步锁,同步锁的对象需要等待上一个同步锁执行完成之后再执行,及synchronized代码块内的内容执行完之后,锁才会释放。 

//问题效率低,传入对象必须等待之前的锁执行完成之后才能执行,无法达到异步的效果
-(void) synchronizedMethod{
    NSObject *obj = [[NSObject alloc]init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized (self) { //锁self
            NSLog(@"同步操作开始!");
            sleep(3);
            NSLog(@"同步操作结束!");
       }
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 1), ^{
        sleep(2);
        @synchronized (obj) {//锁obj
            NSLog(@"同步操作2");
        }
    });
}

 

GCD栅栏应用

在队列中,栅栏块必须单独执行,不能与其他块并行。

这样写readblock和writeblock 有一个好处,耦合性较低并且复用性较强,再其他类里面可以初始化一个GCDAccessor类,直接调用读写方法,在block中读写不同的数据。一个数据对应一个GCDAccessor实例。

但是并行异步会有一个问题存在。

 

//.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface GCDAccessor : NSObject
-(id)readWithGCD:(id(^)(void))readBlock;
-(void)writeWithGCD:(void(^)(void))writeBlock;
@end

NS_ASSUME_NONNULL_END


//.m

#import "GCDAccessor.h"

@interface GCDAccessor ()
@property(nonatomic,strong) dispatch_queue_t syncQueue;
@end


@implementation GCDAccessor
//串行同步队列
-(instancetype)init{
    self = [super init];
    if (self != nil) {
        _syncQueue = dispatch_queue_create("accessor", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

-(id)readWithGCD:(id(^)(void))readBlock{
    __block id readValue = nil;
    dispatch_sync(_syncQueue, ^{
        readValue = readBlock();
    });
    return readValue;
}

-(void)writeWithGCD:(void(^)(void))writeBlock{
    dispatch_barrier_async(_syncQueue, writeBlock);
}

 

使用方式:

@interface ViewController ()<WKNavigationDelegate>
@property (nonatomic,readonly) GCDAccessor *testDataAccessor;
@property (nonatomic) NSMutableDictionary <NSString *,NSString *>* testDic;

@end
- (void)initData{
    _testDataAccessor = [[GCDAccessor alloc]init];
    self.testDic = [NSMutableDictionary<NSString*,NSString*> dictionary];
}

-(void)settestDicWithString:(NSString *)str andKey:(NSString*)key{
    [_testDataAccessor writeWithGCD:^{
        self.testDic = [NSMutableDictionary dictionaryWithObject:str forKey:key];
    }];
}
-(NSString *)gettestDicWithString:(NSString *)str{
    return [_testDataAccessor readWithGCD:^id _Nonnull{
        return self.testDic[str];
    }];
}

相比之下,如果滥用@synchronized(self)很不合适,因为所有同步块(synchroization block)都会彼此抢夺同一个锁。要是有很多属性都这么写的话,那么每个属性的同步块(synchroization block)都要等其他所有同步块(synchroization block)执行完毕才能执行,这也许并不是我想要的效果。

在队列中,栅栏块必须单独执行,不能与其他块并行。这只对并发队列有意义,因为串行本来就是顺序逐个执行的。并发队列如果发现接下来要处理的块是个栅栏块(barrier block),那么久一直要等到当前所有并发块都执行完毕,才会单独执行这个栅栏块,待栅栏块执行过后,再按正常方式继续乡下处理。这也就是说,当我们进行set的时候,这个块是单独执行的,这样就不会出现多个线程同时写入数据的情况。

使用dispatch_barrier 这一套方法,可以适用在各种类里面的对象读写操作。

 

 

iOS - synchronized同步锁和dispatch_barrier应用

上一篇:解决 "Could not autowire. No beans of 'SationMapper' type found" 的问题


下一篇:集成腾讯Bugly日志- Android(1)