iOS -- 多用派发队列, 少用同步锁(25)

多用派发队列, 少用同步锁

在 OC 中,如果有多个线程要执行同一份代码, 那么有时可能会出现问题, 这种情况下, 通常要使用锁来实现某种同步机制, 在 GCD 出现之前, 有两种办法, 第一种是采用内置的 '同步快'.

- (void)synchronizedMethod{

@synchronized(self){

// self

}

}

这种写法会根据给定的对象, 自动创建一个锁,并等待块中的代码执行完毕,执行到这段代码的结尾处, 锁就释放了, 在本例中,同步行文所执行的对象就是 self, 这么写通常没有错, 因为它可以保证每个对象实例都能不受干扰的运行其 synchronizedMethod 方法, 然而,滥用 @synchronized (self) 会降低代码效率, 因为共用同一个锁的那些同步块. 都必须按顺序执行,若是在 self 对象上频繁的加锁, 那么程序可能要等另一段与此无关的代码执行完毕, 才能继续执行当前代码, 这样做其实没有必要.

另一个办法是直接使用 NSLock 对象:

_lock = [[NSLock alloc] init];

- (void)synchronizedMethod{

[_lock lock];

//self

[_lock unlock];

}

也可以使用 NSRecursiveLock 这种 '递归锁',线程能够多次持有该锁,而不会出现死锁现象,

这两种方法都很好,但是都有缺陷

替换方案是使用 GCD, 它能更简单,更高效的形式为代码加锁,那就是使用串行同步队列,

将读取操作及写入操作都安排在同一个队列里面, 即可保证数据同步.其用法如下:

_syncQueue = dispatch_queue_create("com.effectiveobjectivec,syncQueue",NULL);

- (NSString *)someString{

__block NSString *localSomeString;

dispatch_sync(_syncQueue,^{

localSomeString = _someString;

});

return localSomeString;

}

- (void)setSomeString:(NSString *)someString{

dispatch_sync(_syncQueue,^{

_someString = someString;

});

}

总结: 派发队列可用来表述同步语义, 这种做法要比使用 @synchronized 块 或者 NSLock 对象变得更简单.

将同步与异步派发结合起来, 可以实现与普通加锁机制一样的同步行为, 而这么做却不会阻塞执行异步派发的线程.

使用同步队列及栅栏块, 可以令同步行为更加高效,

你可能感兴趣的:(iOS -- 多用派发队列, 少用同步锁(25))