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 这一套方法,可以适用在各种类里面的对象读写操作。