Objective-C 中的线程安全单例 Synchronized()
Thread-Safe Singleton Synchronized() in Objective-C
在我们的应用程序中,我们在多个位置使用了单例,最近我检查并向所有单例方法添加了 @synchronized
命令以确保它们是线程安全的。我的问题是这样调用有什么区别:
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(receiverCache)
{
if (!receiverCache )
receiverCache = [[RLReceiver alloc] init];
return receiverCache;
}
}
在这种情况下,我同步了 class RLReceiver
的静态实例,但我也看到了(编译器令人惊讶地允许)这样的情况:
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(self)
{
if (!receiverCache )
receiverCache = [[RLReceiver alloc] init];
return receiverCache;
}
}
同步开启 self
。这让我有点困惑,因为这个方法是一个 class 方法,而且在这个方法的范围内甚至不应该有 self
。谁能阐明在这种情况下静态变量和 self 之间的区别是什么,以及 class 方法中怎么会有 self ?
根据 Apple 文档:"The object passed to the @synchronized directive is a unique identifier used to distinguish the protected block. If you execute the preceding method in two different threads, passing a different object for the anObj parameter on each thread, each would take its lock and continue processing without being blocked by the other. If you pass the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section."
// 苹果示例:
- (void)myMethod:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
在你的情况下,Hot Licks 所说的问题是第一次启动。您的对象在第一次启动时不存在,并且同步无法正常工作。如果你尝试:
[1]
+(RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(receiverCache)
{
if (!receiverCache ) {
receiverCache = [[RLReceiver alloc] init];
}
for (int i=0; i<100; i++) {
NSLog(@"Numbers in order i %i",i);
}
return receiverCache;
}
}
和[2]
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(self)
{
if (!receiverCache ) {
receiverCache = [[RLReceiver alloc] init];
}
for (int i=0; i<100; i++) {
NSLog(@"Numbers in order i %i",i);
}
return receiverCache;
}
}
来自另一个对象第一次调用类似的东西:
dispatch_async(dispatch_queue_create("OtherQueue", 0), ^{
RLReceiver *rece= [RLReceiver getReceiver];
});
RLReceiver *receSorF = [RLReceiver getReceiver];
您可以看到在 [1] 情况下数字混合和同步是如何不起作用的。在 [2] 的情况下,一个计数等待另一个计数。
我们可以在同步现有对象中的代码时使用该对象,在其他情况下class名称。
谢谢@HotLicks。
在我们的应用程序中,我们在多个位置使用了单例,最近我检查并向所有单例方法添加了 @synchronized
命令以确保它们是线程安全的。我的问题是这样调用有什么区别:
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(receiverCache)
{
if (!receiverCache )
receiverCache = [[RLReceiver alloc] init];
return receiverCache;
}
}
在这种情况下,我同步了 class RLReceiver
的静态实例,但我也看到了(编译器令人惊讶地允许)这样的情况:
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(self)
{
if (!receiverCache )
receiverCache = [[RLReceiver alloc] init];
return receiverCache;
}
}
同步开启 self
。这让我有点困惑,因为这个方法是一个 class 方法,而且在这个方法的范围内甚至不应该有 self
。谁能阐明在这种情况下静态变量和 self 之间的区别是什么,以及 class 方法中怎么会有 self ?
根据 Apple 文档:"The object passed to the @synchronized directive is a unique identifier used to distinguish the protected block. If you execute the preceding method in two different threads, passing a different object for the anObj parameter on each thread, each would take its lock and continue processing without being blocked by the other. If you pass the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section."
// 苹果示例:
- (void)myMethod:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
在你的情况下,Hot Licks 所说的问题是第一次启动。您的对象在第一次启动时不存在,并且同步无法正常工作。如果你尝试:
[1]
+(RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(receiverCache)
{
if (!receiverCache ) {
receiverCache = [[RLReceiver alloc] init];
}
for (int i=0; i<100; i++) {
NSLog(@"Numbers in order i %i",i);
}
return receiverCache;
}
}
和[2]
+ (RLReceiver *) getReceiver
{
static RLReceiver *receiverCache;
@synchronized(self)
{
if (!receiverCache ) {
receiverCache = [[RLReceiver alloc] init];
}
for (int i=0; i<100; i++) {
NSLog(@"Numbers in order i %i",i);
}
return receiverCache;
}
}
来自另一个对象第一次调用类似的东西:
dispatch_async(dispatch_queue_create("OtherQueue", 0), ^{
RLReceiver *rece= [RLReceiver getReceiver];
});
RLReceiver *receSorF = [RLReceiver getReceiver];
您可以看到在 [1] 情况下数字混合和同步是如何不起作用的。在 [2] 的情况下,一个计数等待另一个计数。
我们可以在同步现有对象中的代码时使用该对象,在其他情况下class名称。
谢谢@HotLicks。