@synchronized
结构所做的事情跟锁lock
类似:它防止不同的线程同时执行同一段代码。但在某些情况下,相比于使用 NSLock
创建锁对象、加锁和解锁来说,@synchronized
用着更方便,可读性更高。
@synchronized
的例子
@implementation ThreadSafeQueue
{
NSMutableArray *_elements;
NSLock *_lock;
}
- (instancetype)init
{
self = [super init];
if (self) {
_elements = [NSMutableArray array];
_lock = [[NSLock alloc] init];
}
return self;
}
- (void)push:(id)element
{
[_lock lock];
[_elements addObject:element];
[_lock unlock];
}
@end
i
上面的 ThreadSafeQueue
类有个init
方法,它初始化了一个 _elements
数组和一个 NSLock
实例。
这个类还有个 push:
方法,它先获取锁、然后向数组中插入元素、最终释放锁。可能会有许多线程同时调用 push:
方法,但是[_elements addObject:element]
这行代码在任何时候将只会在一个线程上运行。步骤如下:
1 线程 A 调用 push:
方法
2 线程 B 调用 push:
方法
3 线程 B 调用 [_lock lock]
- 因为当前没有其他线程持有锁,线程 B 获得了锁
4 线程 A 调用 [_lock lock]
,但是锁已经被线程 B 占了所以方法调用并没有返回-这会暂停线程 A 的执行
5 线程 B 向 _elements
添加元素后调用 [_lock unlock]
。当这些发生时,线程 A 的[_lock lock]
方法返回,并继续将自己的元素插入 _elements
。
我们可以用 @synchronized结构更简要地实现这些:
@implementation ThreadSafeQueue
{
NSMutableArray *_elements;
}
- (instancetype)init
{
self = [super init];
if (self) {
_elements = [NSMutableArray array];
}
return self;
}
- (void)increment
{
@synchronized (self) {
[_elements addObject:element];
}
}
@end
在前面的例子中,”synchronized block”
与 [_lock lock]
和 [_lock unlock]
效果相同。你可以把它当成是锁住 self
,仿佛 self就是个 NSLock
。
锁在左括号 {后面的任何代码运行之前被获取到,在右括号 }
后面的任何代码运行之前被释放掉。这爽就爽在妈妈再也不用担心我忘记调用 unlock
了!
你可以给任何 Objective-C
对象上加个 @synchronized
。那么我们也可以在上面的例子中用 @synchronized(_elements)
来替代 @synchronized(self)
,效果是相同的。